001 /** 002 * Copyright (c) 2003 Daffodil Software Ltd all rights reserved, 003 * Modifications Copyright (c) 2008 Regiscope Digital Imaging Co, LLC, All rights reserved. 004 * This program is free software; you can redistribute it and/or modify 005 * it under the terms of version 2 of the GNU General Public License as 006 * published by the Free Software Foundation. 007 * There are special exceptions to the terms and conditions of the GPL 008 * as it is applied to this software. See the GNU General Public License for more details. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU General Public License for more details. 014 * 015 * You should have received a copy of the GNU General Public License 016 * along with this program; if not, write to the Free Software 017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018 */ 019 020 package org.dbreplicator.replication.DBHandler; 021 022 import java.sql.*; 023 import java.util.*; 024 025 import org.dbreplicator.replication.*; 026 import org.dbreplicator.replication.column.*; 027 import org.apache.log4j.Logger; 028 029 /** 030 * In replicator because of the feature of multidatabase synchronization, It has 031 * become very much necessary to handle different databases deifferently. 032 * By identifying the database from Utility class a proper databasehandler is returned, 033 * And every handler extends this abstract class. So the abstract methods declared 034 * in it are defined accordingly in different handlers. 035 * This Class is solely defined for table creations and for appropriate column 036 * datatype sequence generation. 037 * 038 */ 039 040 public abstract class AbstractDataBaseHandler { 041 protected final static String publication_TableName = "Rep_Publications"; 042 protected final static String subscription_TableName = "Rep_Subscriptions"; 043 protected final static String bookmark_TableName = "Rep_BookMarkTable"; 044 protected final static String rep_TableName = "Rep_RepTable"; 045 protected final static String log_Table = "Rep_LogTable"; 046 protected final static String Schedule_TableName = "Rep_ScheduleTable"; 047 public final static String ignoredColumns_Table = "Rep_IgnoredColumnsTable"; 048 public final static String trackReplicationTablesUpdation_Table = "Rep_TrackRepTabUpdation"; 049 public final static String trackPrimaryKeyUpdation_Table = "Rep_trackPrimaryKey"; 050 051 protected ConnectionPool connectionPool; 052 protected String localServerName; 053 protected static int vendorType = -1; 054 protected static Logger log =Logger.getLogger(AbstractDataBaseHandler.class.getName()); 055 /** 056 * Creates Log Table and Rep Table. 057 * @param pubName 058 * @throws SQLException 059 * @throws RepException 060 */ 061 062 abstract protected void createSuperLogTable(String pubName) throws SQLException, RepException; 063 064 abstract protected void createRepTable(String pubName) throws SQLException, RepException; 065 066 public void CreateSequenceOnLogTable(String pubSubName) throws SQLException, 067 RepException { 068 // This method os currently implemented by OracleHandler 069 } 070 071 public void CreateSequenceOnRepTable(String pubSubName) throws SQLException, 072 RepException { 073 // This method os currently implemented by OracleHandler 074 } 075 076 public void CreateSequenceOnShadowTable(String pubSubName) throws 077 SQLException, RepException { 078 // This method os currently implemented by OracleHandler 079 } 080 081 /** 082 * This is a very important function which sets the parameter (instance of 083 * Class TypeInfo) with the corresponding typeName of the sqlType for different 084 * databases. So that we can make corresponding queries. 085 * @param typeInfo 086 * @param rs 087 * @throws RepException 088 * @throws SQLException 089 */ 090 091 abstract public void setTypeInfo(TypeInfo typeInfo, ResultSet rs) throws 092 RepException, SQLException; 093 /** 094 * This method is added for checking of schema.If schema exist in database 095 * then it return true else false.All the database support the schema except 096 * My SQL and Firebird. 097 * @return boolean 098 */ 099 100 abstract public boolean isSchemaSupported(); 101 abstract public boolean isDataTypeOptionalSizeSupported(TypeInfo typeInfo); 102 103 /** 104 * According to the sqlType, different column's for different databases are handled 105 * saperately. It returns the object of AbstractColumnObject which is extended 106 * by each type of column Object classes. This fundamental is used basically for 107 * handeling Blob and Clob type of columns. 108 * @param typeInfo 109 * @throws RepException 110 */ 111 112 abstract public AbstractColumnObject getColumnObject(TypeInfo typeInfo) throws RepException; 113 114 /** 115 * Creates Shadow Table as per the database. 116 * @param pubsubName 117 * @param tableName 118 * @param allColSequence 119 * @throws RepException 120 */ 121 122 abstract public void createShadowTable(String pubsubName, String tableName, String allColSequence,String[] primaryColumns) throws RepException; 123 124 /** 125 * Creates ShadowTable triggers on different replication tables. 126 * @param pubName 127 * @param tableName 128 * @param colNameDataType 129 * @param primCols 130 * @throws RepException 131 */ 132 133 abstract public void createShadowTableTriggers(String pubName, 134 String tableName, 135 ArrayList colNameDataType, 136 String[] primCols) throws RepException; 137 138 abstract public boolean isPrimaryKeyException(SQLException ex) throws SQLException; 139 140 /** 141 * It checks from the sqlType values whether the datatype is optional size 142 * supported or not. 143 * @param connection Connection 144 * @throws RepException 145 */ 146 147 public void setDefaultSchema(Connection connection) throws RepException { 148 // no need to implement, currently daffodildb implements its 149 } 150 151 /** 152 * This method is implemented in child classes if precision exceed the 153 * maximum precision of the data type 154 * @param columnSize int 155 * @throws RepException 156 * @return int 157 */ 158 public int getAppropriatePrecision(int columnSize, String datatypeName) { 159 return columnSize; 160 } 161 162 public void createRemoteSystemTables(String pubName) throws RepException { 163 try { 164 createPublicationTable(pubName); 165 } 166 catch (RepException ex) { 167 throw ex; 168 } 169 catch (SQLException ex) { 170 // Ignore the Exception, System Table alredy exists. 171 } 172 try { 173 createBookMarkTable(pubName); 174 } 175 catch (RepException ex1) { 176 throw ex1; 177 } 178 catch (SQLException ex1) { 179 // Ignore the Exception, System Table alredy exists. 180 } 181 try { 182 createSuperLogTable(pubName); 183 } 184 catch (RepException ex2) { 185 throw ex2; 186 } 187 catch (SQLException ex2) { 188 // Ignore the Exception, System Table alredy exists. 189 } 190 191 try { 192 CreateSequenceOnLogTable(pubName); 193 } 194 catch (RepException ex4) { 195 throw ex4; 196 } 197 catch (SQLException ex4) { 198 } 199 200 try { 201 createRepTable(pubName); 202 } 203 catch (RepException ex3) { 204 throw ex3; 205 } 206 catch (SQLException ex3) { 207 // Ignore the Exception, System Table alredy exists. 208 } 209 try { 210 CreateSequenceOnRepTable(pubName); 211 } 212 catch (RepException ex5) { 213 throw ex5; 214 } 215 catch (SQLException ex5) { 216 } 217 218 try { 219 createIgnoredColumnsTable(pubName); 220 } 221 catch (RepException ex6) { 222 throw ex6; 223 } 224 catch (SQLException ex6) { 225 } 226 227 // work for TrackReplicationTablesUpdation table 228 try { 229 createTrackReplicationTablesUpdationTable(pubName); 230 } 231 catch (RepException ex5) { 232 throw ex5; 233 } 234 catch (SQLException ex5) { 235 } 236 // trigger for track table 237 try { 238 createTriggerForTrackReplicationTablesUpdationTable(pubName); 239 } 240 catch (RepException ex5) { 241 throw ex5; 242 } 243 catch (SQLException ex5) { 244 } 245 246 247 } 248 249 public int getvendorName() { 250 return vendorType; 251 } 252 253 public void createClientSystemTables(String subName) throws RepException { 254 try { 255 createSubscriptionTable(subName); 256 } 257 catch (RepException ex) { 258 throw ex; 259 } 260 catch (SQLException ex) { 261 RepConstants.writeERROR_FILE(ex); 262 // Ignore the Exception, System Table alredy exists. 263 } 264 try { 265 createBookMarkTable(subName); 266 } 267 catch (RepException ex1) { 268 throw ex1; 269 } 270 catch (SQLException ex1) { 271 // Ignore the Exception, System Table alredy exists. 272 } 273 try { 274 createSuperLogTable(subName); 275 } 276 catch (RepException ex2) { 277 throw ex2; 278 } 279 catch (SQLException ex2) { 280 // Ignore the Exception, System Table alredy exists. 281 } 282 283 try { 284 CreateSequenceOnLogTable(subName); 285 } 286 catch (RepException ex4) { 287 throw ex4; 288 } 289 catch (SQLException ex4) {} 290 try { 291 createRepTable(subName); 292 } 293 catch (RepException ex3) { 294 throw ex3; 295 } 296 catch (SQLException ex3) { 297 // Ignore the Exception, System Table alredy exists. 298 } 299 try { 300 CreateSequenceOnRepTable(subName); 301 } 302 catch (RepException ex5) { 303 throw ex5; 304 } 305 catch (SQLException ex5) {} 306 try { 307 createScheduleTable(subName); 308 } 309 catch (RepException ex) { 310 throw ex; 311 } 312 catch (SQLException ex5) { 313 } 314 315 try { 316 createIgnoredColumnsTable(subName); 317 } 318 catch (RepException ex6) { 319 throw ex6; 320 } 321 catch (SQLException ex6) { 322 } 323 324 // work for TrackReplicationTablesUpdation table 325 try { 326 createTrackReplicationTablesUpdationTable(subName); 327 } 328 catch (RepException ex5) { 329 throw ex5; 330 } 331 catch (SQLException ex5) { 332 } 333 // trigger for track table 334 try { 335 createTriggerForTrackReplicationTablesUpdationTable(subName); 336 } 337 catch (RepException ex5) { 338 throw ex5; 339 } 340 catch (SQLException ex5) { 341 } 342 } 343 344 345 346 protected void createPublicationTable(String pubName) throws RepException, SQLException { 347 StringBuffer pubsTableQuery = new StringBuffer(); 348 pubsTableQuery.append(" Create Table ") 349 .append(getPublicationTableName()) 350 .append(" ( " + RepConstants.publication_pubName1 + " varchar(255) , " + 351 RepConstants.publication_conflictResolver2 + " varchar(255) , ") 352 .append(" " + RepConstants.publication_serverName3 + 353 " varchar (255) , Primary Key (" + 354 RepConstants.publication_pubName1 + ") ) "); 355 runDDL(pubName, pubsTableQuery.toString()); 356 } 357 358 protected void createSubscriptionTable(String pubName) throws RepException, 359 SQLException { 360 String subsTableQuery = " Create Table " 361 + getSubscriptionTableName() 362 + " ( " + RepConstants.subscription_subName1 + " varchar(255) , " 363 + " " + RepConstants.subscription_pubName2 + " varchar(255) , " 364 + " " + RepConstants.subscription_conflictResolver3 + 365 " varchar(255) , " 366 + " " + RepConstants.subscription_serverName4 + " varchar (255) , " 367 + " Primary Key (" + RepConstants.subscription_subName1 + ") ) "; 368 runDDL(pubName, subsTableQuery); 369 } 370 371 protected void createBookMarkTable(String pubName) throws SQLException, 372 RepException { 373 StringBuffer bookmarkTableQuery = new StringBuffer(); 374 bookmarkTableQuery.append(" Create Table ") 375 .append(getBookMarkTableName()) 376 .append(" ( " + RepConstants.bookmark_LocalName1 + " varchar(255) , " + 377 RepConstants.bookmark_RemoteName2 + " varchar(255) , ") 378 .append(" " + RepConstants.bookmark_TableName3 + " varchar(255) , " + 379 RepConstants.bookmark_lastSyncId4 + " Long , ") 380 .append(" " + RepConstants.bookmark_ConisderedId5 + 381 " Long ,"+RepConstants.bookmark_IsDeletedTable+" char(1) default 'N' , Primary Key (" + RepConstants.bookmark_LocalName1 + 382 ", " + RepConstants.bookmark_RemoteName2 + ", " + 383 RepConstants.bookmark_TableName3 + ") ) "); 384 runDDL(pubName, bookmarkTableQuery.toString()); 385 } 386 387 protected void createScheduleTable(String subName) throws SQLException, 388 RepException { 389 StringBuffer ScheduleTableQuery = new StringBuffer(); 390 ScheduleTableQuery.append(" Create Table ") 391 .append(getScheduleTableName()) 392 .append(" ( " + RepConstants.schedule_Name + " varchar(255) , " + 393 RepConstants.subscription_subName1 + " varchar(255) unique , ") 394 .append(" " + RepConstants.schedule_type + " varchar(255) , ") 395 .append(" " + RepConstants.publication_serverName3 + " varchar (255) ," + 396 RepConstants.publication_portNo + " varchar(255) ,") 397 .append(" " + RepConstants.recurrence_type + " varchar(255) , " + 398 RepConstants.replication_type + " varchar(255) ,") 399 .append(" " + RepConstants.schedule_time + " Long , ") 400 .append(" " + RepConstants.schedule_counter + " Long , Primary Key (" + 401 RepConstants.schedule_Name + " , " + 402 RepConstants.subscription_subName1 + ") ) "); 403 runDDL(subName, ScheduleTableQuery.toString()); 404 } 405 406 void runDDL(String pubsubName, String query) throws SQLException, RepException { 407 Connection connection = connectionPool.getConnection(pubsubName); 408 Statement stt = connection.createStatement(); 409 try { 410 log.debug(query); 411 //System.out.println(" ***********************************************************************************"); 412 //System.out.println(" "); 413 //System.out.println(" query ="+query); 414 //System.out.println(" "); 415 //System.out.println(" ***********************************************************************************"); 416 stt.execute(query); 417 log.info("Query executed "+query); 418 //System.out.println(" QUERY EXECUTED SUCCESSFULLY "); 419 420 } 421 finally { 422 //bjt - don't run removeSubPubFromMap because it sets connection to null and 423 //forces connection pooling to create a new connection. This means when 424 //creating a new publication the number of open database connections jumps to 425 //something like 2x number of published tables. 426 //connectionPool.removeSubPubFromMap(pubsubName); 427 if(stt!=null) 428 stt.close(); 429 connectionPool.returnConnection(connection); 430 } 431 } 432 433 /** 434 * This method create the main table, its corresponding shadow table and 435 * triggers in the database. If main table already created in the database, 436 * then it get existing table query. If table structure is same then it 437 * subscribe the table in database otherwise it thorw the exception table 438 * already exist with different structure the database. 439 * @param subName String 440 * @param pubTableQueries String[] 441 * @param primCols HashMap 442 * @param pubVendorType int 443 * @throws RepException 444 * @throws SQLException 445 */ 446 public void createSubscribedTablesTriggersAndShadowTables(String subName, 447 String[] pubTableQueries,String[] alterTableAddFKQueries,HashMap primCols, int pubVendorType,ArrayList repTables) throws RepException, SQLException { 448 Connection connection = connectionPool.getConnection(subName); 449 Statement stt = connection.createStatement(); 450 try 451 { 452 for (int i = 0; i < pubTableQueries.length; i++) { 453 try { 454 stt.execute(pubTableQueries[i]); 455 } 456 catch (SQLException ex) { 457 /* SchemaQualifiedName sname = new SchemaQualifiedName(mdi, getTableName(pubTableQueries[i])); 458 // MetaDataInfo mdi = new MetaDataInfo(connection); 459 >>>>>>> 1.67.6.4 460 String existing = null; 461 ArrayList foreignKeyQueries=new ArrayList(); 462 try { 463 existing = mdi.getExistingTableQuery(this, sname, pubVendorType); 464 ArrayList alterTabelStatements = mdi.getForeignKeyConstraints(sname.getSchemaName(), sname.getTableName()); 465 // System.out.println("Getting the query : " + alterTabelStatements); 466 if (alterTabelStatements != null && alterTabelStatements.size() > 0) { 467 foreignKeyQueries.addAll(alterTabelStatements); 468 } 469 //System.out.println(" existing Query =" + existing); 470 existing = existing.toLowerCase().replaceAll(" ", ""); 471 } 472 catch (RepException ex1) { 473 if (ex1.getRepCode().equalsIgnoreCase("REP033")) { 474 throw ex; 475 } 476 } 477 //System.out.println(" pubTableQueries[i] =" + pubTableQueries[i]); 478 479 /* if (pubTableQueries[i].toLowerCase().replaceAll(" ", 480 "").indexOf(existing.toLowerCase()) != 0) { 481 throw new RepException("REP024", new Object[] {subName, 482 sname.toString()}); 483 } */ 484 // Ignore the exception if the same table exists with same colums and primary key 485 } 486 } 487 if(alterTableAddFKQueries != null){ 488 for (int i = 0, size = alterTableAddFKQueries.length; i < size; i++) { 489 try { 490 //System.out.println(" alterTableQueries ="+alterTableAddFKQueries[i]); 491 stt.execute(alterTableAddFKQueries[i]); 492 493 } 494 catch (SQLException ex) { 495 /** @todo 496 * if it is required ti check for existence of foreign constraint 497 * then we have to get the constraint name and check whether it is defined as required 498 * if not then give any other name to the constraint and add it or throw exception 499 * */ 500 // ex.printStackTrace(); 501 // Ignore the exception if the constraint is already made 502 } 503 } 504 } 505 } finally { 506 if(stt!=null) 507 stt.close(); 508 connectionPool.returnConnection(connection); 509 } 510 // Just Get the Column Sequenes from Create Table Queries 511 // and create Shadow Table and Triggers on Shadow Table 512 try 513 { 514 connection = connectionPool.getConnection(subName); 515 MetaDataInfo mdi = Utility.getDatabaseMataData(connection); 516 for (int i = 0; i < pubTableQueries.length; i++) { 517 RepTable reptable=(RepTable)repTables.get(i); 518 if(reptable.getCreateShadowTable().equalsIgnoreCase(RepConstants.NO)) 519 continue ; 520 String tableName = getTableName(pubTableQueries[i]); 521 SchemaQualifiedName sname = new SchemaQualifiedName(mdi,getTableName(pubTableQueries[i])); 522 String colSeqenceWithDataType = getColumnSequenceWithDataTypes(pubTableQueries[i]); 523 ArrayList colInfoList = getColumnNamesAndDataTypes(colSeqenceWithDataType.trim()); 524 for (int cnt = 0; cnt < colInfoList.size(); cnt++) { 525 log.debug("column "+cnt+" - "+( (ColumnsInfo) colInfoList.get(cnt)).getColumnName()+" "+((ColumnsInfo) colInfoList.get(cnt)).getDataTypeDeclaration()); 526 } 527 String[] pcols = (String[]) ( (ArrayList) primCols.get(tableName.toLowerCase())).toArray(new String[0]); 528 String allColSequence = getShadowTableColumnDataTypeSequence(colInfoList,pcols,reptable); 529 createShadowTable(subName, sname.toString(), allColSequence,pcols); 530 makeProvisionForLOBDataTypes(colInfoList); 531 createShadowTableTriggers(subName, sname.toString(), colInfoList, pcols); 532 //createShadowTablesAndSubscriptionTableTriggers(subName,tableName,colSeqenceWithDataType,(ArrayList) primCols.get(tableName.toLowerCase())); 533 } 534 } 535 finally { 536 connectionPool.returnConnection(connection); 537 } 538 } 539 540 541 /** 542 * Get the main table name from CreateTableQuery 543 * @param createTableQuery String 544 * @return String 545 */ 546 String getTableName(String createTableQuery) { 547 int startIndex = createTableQuery.toLowerCase().indexOf("table") + 5 ; 548 int endIndex = createTableQuery.indexOf("(") - 1; 549 return createTableQuery.substring(startIndex, endIndex).trim(); 550 } 551 552 String getColumnSequenceWithDataTypes(String createTableQuery) { 553 int startIndex = createTableQuery.indexOf("(") + 1; 554 int endIndex = createTableQuery.toLowerCase().indexOf("primary key") - 1; 555 return createTableQuery.substring(startIndex, endIndex).trim(); 556 } 557 558 /** 559 * Return the list of shadowtabls cols in a string. 560 * @param nameTypeList ArrayList 561 * @param primCols String[] 562 * @return String 563 */ 564 public String getShadowTableColumnDataTypeSequence(ArrayList nameTypeList, String[] primCols,RepTable reptable) { 565 StringBuffer toRet = new StringBuffer(); 566 toRet.append(getColumnDataTypeSequence(nameTypeList,reptable)) 567 .append(getPrimaryColumnDataTypeSequence(primCols,"rep_old_")); 568 return toRet.toString(); 569 } 570 571 protected String getPrimaryColumnDataTypeSequence(String[] primCols,String prefix) { 572 StringBuffer toRet = new StringBuffer(); 573 for (int i = 0, size = primCols.length; i < size; i++) { 574 toRet.append(" , ").append(prefix).append(primCols[i]).append(" ") 575 .append(ColumnsInfo.getDataTypeDeclaration(primCols[i])); 576 } 577 return toRet.toString(); 578 } 579 //we will also set allColumns list in Reptable in this method alongwith getting column datatype Sequence 580 private String getColumnDataTypeSequence(ArrayList colTypeMap,RepTable reptable) { 581 StringBuffer toRet = new StringBuffer(); 582 String[] allColumns=new String[colTypeMap.size()]; 583 for (int i = 0, size = colTypeMap.size(); i < size; i++) { 584 ColumnsInfo ci = (ColumnsInfo) colTypeMap.get(i); 585 String colName = ci.getColumnName(); 586 allColumns[i]=colName; 587 toRet.append(" , ").append(colName).append(" ") 588 .append(ci.getDataTypeDeclaration()); 589 } 590 reptable.setAllColumns(allColumns); 591 return toRet.toString(); 592 } 593 594 private String[] getColumnsNames(String columnSeqWithDataTypes) { 595 ArrayList colNames = new ArrayList(); 596 do { 597 int index = columnSeqWithDataTypes.indexOf(" "); 598 int commaIndex = columnSeqWithDataTypes.indexOf(","); 599 if (index == -1 || commaIndex == -1) { 600 return (String[]) colNames.toArray(new String[0]); 601 } 602 colNames.add(columnSeqWithDataTypes.substring(0, index).trim()); 603 columnSeqWithDataTypes = columnSeqWithDataTypes.substring(commaIndex + 1).trim(); 604 } 605 while (true); 606 } 607 608 // creating a columns sequence col1[,col2[,col3,...]] to be used for all shadow table trigger 609 String getColumnNameSequence(String[] columnNames, String prefix) { 610 StringBuffer sb = new StringBuffer(); 611 for (int i = 0; i < columnNames.length; i++) { 612 sb.append(prefix).append(columnNames[i]).append(" , "); 613 } 614 return sb.toString(); 615 } 616 617 String[] getColumnNameWithOldOrNewPrefix(String[] columnNames, String prefix) { 618 String[] sb = new String[columnNames.length]; 619 for (int i = 0; i < columnNames.length; i++) { 620 sb[i] = prefix+columnNames[i]; 621 } 622 return sb; 623 } 624 625 626 public void setLocalServerName(String name0) { 627 localServerName = name0; 628 } 629 630 public String getLocalServerName() { 631 return localServerName; 632 } 633 634 /** 635 * Save the RepTable data which is a system table. 636 * It store the Publication/Subscription Name, 637 * its corresponding table with filter clause and conflict 638 * resolver. 639 */ 640 641 public String saveRepTableData(Connection connection, String pubsubName, RepTable repTable) throws SQLException, RepException { 642 StringBuffer sb = new StringBuffer(); 643 PreparedStatement repPreparedStmt =null; 644 String filter = repTable.getFilterClause(); 645 String[] ignoredColumns = repTable.getColumnsToBeIgnored(); 646 if (filter != null) { 647 if (!filter.equalsIgnoreCase("")) { 648 649 // Rep_PubSub_Name 650 // Rep_Table_Id 651 // Rep_Table_Name 652 // Rep_filter_clause 653 // Rep_createshadowtable 654 // Rep_cyclicdependency 655 // Rep_conflict_resolver 656 657 658 sb.append("insert into ").append(getRepTableName()) 659 .append(" ( ").append(RepConstants.repTable_pubsubName1).append(" , ") 660 .append(RepConstants.repTable_tableName2).append(" , ") 661 .append(RepConstants.repTable_filter_clause3).append(" , ") 662 .append(RepConstants.repTable_createshadowtable6).append(" , ") 663 .append(RepConstants.repTable_cyclicdependency7).append(" , ") 664 .append(RepConstants.repTable_conflict_resolver4).append(" ) ") 665 .append(" values ( ?,?,?,?,?,?) "); 666 repPreparedStmt = connection.prepareStatement(sb.toString()); 667 repPreparedStmt.setString(1, pubsubName); 668 repPreparedStmt.setString(2, repTable.getSchemaQualifiedName().toString()); 669 repPreparedStmt.setString(3, repTable.getFilterClause()); 670 repPreparedStmt.setString(4, repTable.getCreateShadowTable()); 671 //System.out.println("AbstractDataBaseHandler.saveRepTableData(connection, pubsubName, repTable) hashCode ="+repTable.hashCode() +" cyclic dependency ="+repTable.getCyclicDependency() ); 672 repPreparedStmt.setString(5, repTable.getCyclicDependency()); 673 repPreparedStmt.setString(6, repTable.getConflictResolver()); 674 repPreparedStmt.execute(); 675 log.info("Query exceuted"+sb.toString()); 676 log.info(pubsubName); 677 log.info(repTable.getSchemaQualifiedName().toString()); 678 log.info(repTable.getFilterClause()); 679 log.info(repTable.getConflictResolver()); 680 681 } 682 } 683 else { 684 sb.append("insert into ").append(getRepTableName()).append(" ( ") 685 .append(RepConstants.repTable_pubsubName1).append(" , ") 686 .append(RepConstants.repTable_tableName2).append(" , ") 687 .append(RepConstants.repTable_createshadowtable6).append(" , ") 688 .append(RepConstants.repTable_cyclicdependency7).append(" , ") 689 .append(RepConstants.repTable_conflict_resolver4).append(" ) ") 690 .append(" values(?,?,?,?,?)"); 691 repPreparedStmt = connection.prepareStatement(sb.toString()); 692 repPreparedStmt.setString(1, pubsubName); 693 repPreparedStmt.setString(2, repTable.getSchemaQualifiedName().toString()); 694 repPreparedStmt.setString(3, repTable.getCreateShadowTable()); 695 repPreparedStmt.setString(4, repTable.getCyclicDependency()); 696 repPreparedStmt.setString(5, repTable.getConflictResolver()); 697 repPreparedStmt.execute(); 698 } 699 /** @todo statement has been closed */ 700 repPreparedStmt.close(); 701 if(ignoredColumns != null){ 702 int tableId = getRepTableId(connection, pubsubName, repTable); 703 String queryToInsert="INSERT INTO "+getIgnoredColumns_Table()+ " VALUES ( ?, ?)"; 704 PreparedStatement statementToInsert= connection.prepareStatement(queryToInsert); 705 for (int i = 0,size=ignoredColumns.length; i < size; i++) { 706 statementToInsert.setInt(1,tableId); 707 statementToInsert.setString(2,ignoredColumns[i]); 708 statementToInsert.execute(); 709 } 710 } 711 return sb.toString(); 712 } 713 714 public void setIgnoredColumns(Connection connection,String pubsubName,RepTable repTable) throws RepException,SQLException{ 715 int tableId = getRepTableId(connection, pubsubName, repTable); 716 ArrayList columnsToBeIgnored=new ArrayList(); 717 StringBuffer sb = new StringBuffer(); 718 sb.append("SELECT ") 719 .append(RepConstants.ignoredColumnsTable_ignoredcolumnName2) 720 .append(" FROM ") 721 .append(getIgnoredColumns_Table()) 722 .append(" WHERE ") 723 .append(RepConstants.ignoredColumnsTable_tableId1) 724 .append(" = ") 725 .append(tableId); 726 // String query="SELECT "+RepConstants.ignoredColumnsTable_ignoredcolumnName2+" FROM "+getIgnoredColumns_Table()+ " WHERE " +RepConstants.ignoredColumnsTable_tableId1 +" = "+tableId; 727 Statement statement=connection.createStatement(); 728 ResultSet rs=statement.executeQuery(sb.toString()); 729 while(rs.next()){ 730 String columnName = rs.getString(1); 731 //System.out.println("Adding the column in the list : " + columnName); 732 columnsToBeIgnored.add(columnName); 733 } 734 repTable.setColumnsToBeIgnored((String[])columnsToBeIgnored.toArray(new String[0])); 735 rs.close(); 736 statement.close(); 737 } 738 739 private int getRepTableId(Connection connection, String pubsubName, RepTable repTable) throws SQLException { 740 StringBuffer sb =new StringBuffer(); 741 sb.append("SELECT ") 742 .append(RepConstants.repTable_tableId2) 743 .append(" FROM ") 744 .append(RepConstants.rep_TableName) 745 .append(" WHERE ") 746 .append(RepConstants.repTable_pubsubName1) 747 .append(" = '") 748 .append(pubsubName) 749 .append("' AND ") 750 .append(RepConstants.repTable_tableName2) 751 .append(" = '") 752 .append(repTable.getSchemaQualifiedName().toString()) 753 .append("'"); 754 // String queryToGetTableId="SELECT "+RepConstants.repTable_tableId2+" FROM "+RepConstants.rep_TableName+ " WHERE " + RepConstants.repTable_pubsubName1 +" = ?"+" AND "+RepConstants.repTable_tableName2+" = ?" ; 755 // PreparedStatement statement = connection.prepareStatement(queryToGetTableId); 756 Statement statement = connection.createStatement(); 757 // statement.setString(1,pubsubName); 758 // statement.setString(2,repTable.getSchemaQualifiedName().toString()); 759 ResultSet rs= statement.executeQuery(sb.toString()); 760 rs.next(); 761 int tableId=rs.getInt(1); 762 rs.close(); 763 statement.close(); 764 return tableId; 765 } 766 767 protected Object getQuotedStringData(Object value) { 768 if (value == null) { 769 return value; 770 } 771 return "'" + value + "'"; 772 } 773 774 protected HashMap schemas; 775 776 public boolean checkSchema(String schemaName) { 777 if (schemas == null) { 778 schemas = new HashMap(); 779 schemas.put(schemaName.toLowerCase(), ""); 780 return false; 781 } 782 if (schemas.containsKey(schemaName.toLowerCase())) { 783 return true; 784 } 785 schemas.put(schemaName.toLowerCase(), ""); 786 return false; 787 } 788 789 public void dropTriggersAndShadowTable(Connection connection, String table, String pubsubName) throws SQLException, RepException { 790 String tableName = table.substring(table.indexOf('.') + 1); 791 fireDropQuery(connection, " drop trigger " + RepConstants.getInsertTriggerName(table)); 792 fireDropQuery(connection, " drop trigger " + RepConstants.getDeleteTriggerName(table)); 793 fireDropQuery(connection, " drop trigger " + RepConstants.getUpdateTriggerName(table)); 794 fireDropQuery(connection, " drop table " + RepConstants.shadow_Table(table)); 795 dropSequences(connection,RepConstants.seq_Name(RepConstants.shadow_Table(tableName))); 796 dropGenerators(connection,RepConstants.gen_Name(RepConstants.shadow_Table(tableName))); 797 fireDropQuery(connection, " delete from " + getLogTableName() + " where " +RepConstants.logTable_tableName2 + " = '" + table + "'"); 798 799 } 800 801 public void fireDropQuery(Connection con, String query) throws SQLException { 802 Statement stt = con.createStatement(); 803 try { 804 stt.execute(query); 805 log.info("query executed "+query); 806 } 807 catch (SQLException sqlEx) { 808 // Ignore the Exception 809 } 810 finally { 811 stt.close(); 812 } 813 } 814 815 /*public void writeSchemaName(OutputStreamWriter os, String schemaName) throws 816 java.io.IOException { 817 if (schemas == null) { 818 os.write("<SchemaName>"); 819 os.write(schemaName); 820 os.write("</SchemaName>"); 821 schemas = new HashMap(); 822 schemas.put(schemaName.toLowerCase(), ""); 823 return; 824 } 825 if (schemas.containsKey(schemaName.toLowerCase())) 826 return; 827 os.write("<SchemaName>"); 828 os.write(schemaName); 829 os.write("</SchemaName>"); 830 }*/ 831 832 public String updateDataType(String dataType0) { 833 return dataType0; 834 } 835 836 // Current this method is implemented by Daffodildb and PostgreSQL 837 public void createSchemas(String pubName, ArrayList schemas) throws SQLException, RepException { 838 } 839 840 public void dropSequences(Connection con, String sequenceName) throws SQLException { 841 } 842 843 public void makeProvisionForLOBDataTypes(ArrayList list) { 844 } 845 846 public String getPublicationTableName() { 847 return publication_TableName; 848 } 849 850 public String getSubscriptionTableName() { 851 return subscription_TableName; 852 } 853 854 public String getRepTableName() { 855 return rep_TableName; 856 } 857 858 public String getLogTableName() { 859 return log_Table; 860 } 861 862 public String getBookMarkTableName() { 863 return bookmark_TableName; 864 } 865 866 public String getScheduleTableName() { 867 return Schedule_TableName; 868 } 869 870 public void setColumnPrecisionInTypeInfo(TypeInfo typeInfo, ResultSetMetaData rsmt, int columnIndex) throws SQLException { 871 // not implmented . child class sql server, daffodildb,and oracle implement it 872 } 873 874 public ArrayList getColumnNamesAndDataTypes1(String columnSequence) { 875 // col1 datatyoe, colName datatype 876 ArrayList list = new ArrayList(); 877 String lowerString ; 878 do { 879 lowerString = columnSequence.toLowerCase(); 880 int startIndex = columnSequence.indexOf(" "); 881 int lastIndex = columnSequence.indexOf(" , "); 882 883 int notNullIndex = lowerString.indexOf("not null"); 884 String name = columnSequence.substring(0, startIndex); 885 String dataType = ""; 886 if (notNullIndex != -1 && notNullIndex < lastIndex) { 887 dataType = columnSequence.substring(startIndex + 1, notNullIndex - 1); 888 } 889 else { 890 dataType = columnSequence.substring(startIndex + 1, lastIndex - 1); 891 } 892 int defaultIndex = dataType.toLowerCase().indexOf("default "); 893 894 if(defaultIndex != -1 ){ 895 dataType = dataType.substring(0, defaultIndex); 896 } 897 list.add(new ColumnsInfo(name, dataType)); 898 columnSequence = columnSequence.substring(lastIndex + 1).trim(); 899 } 900 while (columnSequence.length() > 0); return list; 901 } 902 903 public String getTableColumns(int VendorType, String columnName, TypeInfo typeInfo, int columnPrecision, ResultSet rs) throws RepException, SQLException { 904 StringBuffer sb = new StringBuffer(); 905 sb.append(columnName).append(" ").append(typeInfo.getTypeDeclaration(columnPrecision)); 906 return sb.toString(); 907 } 908 909 public String getShadowTableName(String tableName) { 910 return RepConstants.shadow_Table(tableName); 911 } 912 913 /** 914 * Create index on syn_id column of shadowTable to 915 * improve the performance of Replicator Operation 916 * @param tableName 917 * @param columnName 918 */ 919 920 abstract protected void createIndex(String pubsubName,String tableName) throws RepException ; 921 //to handle the column scale 922 public ArrayList getColumnNamesAndDataTypes(String columnSequence) { 923 // col1 datatyoe, colName datatype 924 ArrayList list = new ArrayList(); 925 String lowerString = columnSequence; 926 do { 927 lowerString = columnSequence.toLowerCase(); 928 int startIndex = columnSequence.indexOf(" "); 929 int lastIndex = columnSequence.indexOf(","); /* get a supposed lastIndex */ 930 /* loop through, using indexOf(int ch, int fromIndex), to find all the closed ')' for each open '(' */ 931 int openIndex = startIndex; 932 int closeIndex = startIndex; 933 int i=0; int nextIndex = 0; 934 while (nextIndex < lastIndex) { 935 openIndex = nextIndex; 936 i++; /* we've got at least one that's less than lastIndex, so we'll need to check 937 to make sure they all close before lastIndex */ 938 nextIndex = columnSequence.indexOf("(",nextIndex+1); 939 if (nextIndex == -1) break; /* last open paren of the whole string */ 940 } 941 i--; /* decrement the counter, b/c it counted the first instance, even if no open paren was found */ 942 while (i > 0) { 943 closeIndex = columnSequence.indexOf(")",closeIndex+1); 944 i--; 945 } 946 /* if the last closing paren is after the comma, find the next one after the last closing paren */ 947 if (closeIndex > lastIndex) lastIndex = columnSequence.indexOf(",",closeIndex); 948 949 int notNullIndex = lowerString.indexOf("not null"); 950 String name = columnSequence.substring(0, startIndex); 951 String dataType = ""; 952 if (notNullIndex != -1 && notNullIndex < lastIndex) { 953 /* if we've got a not null */ 954 dataType=columnSequence.substring(startIndex + 1, notNullIndex-1 ); 955 if(dataType.indexOf("(")!=-1){ 956 if(dataType.indexOf(")")==-1){ 957 String dataType1 = columnSequence.substring(notNullIndex + 1).trim(); 958 959 dataType = dataType + " , " + dataType1.substring(dataType1.indexOf(" ")+1, (dataType1.indexOf(",")-1)); 960 lastIndex= lastIndex=(lastIndex+1)+dataType1.indexOf(" ,");//(lastIndex+1)+dataType1.length()-1; 961 }else{ 962 dataType = columnSequence.substring(startIndex + 1, notNullIndex-1 ); 963 } 964 }else{ 965 dataType = columnSequence.substring(startIndex + 1, notNullIndex-1 ); 966 } 967 } 968 else{ 969 /* no 'not null' string */ 970 dataType=columnSequence.substring(startIndex + 1, lastIndex-1 ); 971 log.debug("name = "+name+", dataType = "+dataType); 972 /* 973 if(dataType.indexOf("(")!=-1){ 974 if(dataType.indexOf(")")==-1){ 975 String dataType1 =columnSequence.substring(lastIndex+1); 976 dataType = dataType + " , " + dataType1.substring((dataType1.indexOf(" ")+1), (dataType1.indexOf(",")-1)); 977 lastIndex= lastIndex=(lastIndex+1)+dataType1.indexOf(",");//(lastIndex+1)+dataType1.length()-1; 978 }else{ 979 dataType = columnSequence.substring(startIndex + 1, lastIndex-1 ); 980 System.out.println("bjt2, dataType - "+dataType); 981 } 982 }else{ 983 984 dataType = columnSequence.substring(startIndex + 1, lastIndex-1 ); 985 System.out.println("bjt3, dataType - "+dataType); 986 } 987 */ 988 } 989 list.add(new ColumnsInfo(name, dataType)); 990 columnSequence = columnSequence.substring(lastIndex + 1).trim(); 991 } 992 while (columnSequence.length() > 0); 993 return list; 994 } 995 996 //if precison is less than scale ,Exception will be thrown to user depending on subscriber databse 997 //---as suggested by Parveen Sir 998 abstract public int getAppropriateScale(int columnScale) throws RepException; 999 1000 public void dropPublisherSystemTables(Connection con) { 1001 try { 1002 fireDropQuery(con, " drop table " + getPublicationTableName()); 1003 fireDropQuery(con, " drop table " + getBookMarkTableName()); 1004 fireDropQuery(con, " drop table " + getRepTableName()); 1005 fireDropQuery(con, " drop table " + getLogTableName()); 1006 fireDropQuery(con, " drop table " + getIgnoredColumns_Table()); 1007 fireDropQuery(con, " drop table " + getTrackReplicationTablesUpdation_Table()); 1008 fireDropQuery(con, " drop table " + getTrackPrimayKeyUpdation_Table()); 1009 } 1010 catch (Exception ex) { 1011 } 1012 } 1013 public void dropSubscriberSystemTables(Connection con) { 1014 try { 1015 fireDropQuery(con, " drop table " + getSubscriptionTableName()); 1016 fireDropQuery(con, " drop table " + getBookMarkTableName()); 1017 fireDropQuery(con, " drop table " + getRepTableName()); 1018 fireDropQuery(con, " drop table " + getLogTableName()); 1019 fireDropQuery(con, " drop table " + getScheduleTableName()); 1020 fireDropQuery(con, " drop table " + getIgnoredColumns_Table()); 1021 fireDropQuery(con, " drop table " + getTrackReplicationTablesUpdation_Table()); 1022 fireDropQuery(con, " drop table " + getTrackPrimayKeyUpdation_Table()); 1023 } 1024 catch (Exception ex) { 1025 } 1026 } 1027 1028 public void deleteRecordsFromSuperLogTable(Statement subStatment) throws 1029 SQLException { 1030 // insert one record in superLogTable 1031 1032 StringBuffer query = new StringBuffer(); 1033 query.append("insert into ").append(getLogTableName()).append( 1034 " ("). 1035 append(RepConstants.logTable_tableName2).append( 1036 ") values ('$$$$$$')"); 1037 1038 subStatment.execute(query.toString()); 1039 1040 query = new StringBuffer(); 1041 // deleting all but one last record from super log table where commonid is maximum 1042 query.append("Select max(").append(RepConstants.logTable_commonId1). 1043 append(") from ").append(getLogTableName()); 1044 ResultSet rs = subStatment.executeQuery(query.toString()); 1045 rs.next(); 1046 long maxCID = rs.getLong(1); 1047 1048 query = new StringBuffer(); 1049 1050 query.append("delete from ").append(getLogTableName()).append( 1051 " where ") 1052 .append(RepConstants.logTable_commonId1).append(" !=").append(maxCID); 1053 subStatment.executeUpdate(query.toString()); 1054 log.debug(query.toString()); 1055 } 1056 1057 1058 1059 1060 1061 public void dropGenerators(Connection con, String generatorName) throws SQLException { 1062 } 1063 1064 /** 1065 * To get the foreign key error code to resolve 1066 * the Synchronization problem when tables have 1067 * parent - child relationship. 1068 * @return String 1069 */ 1070 abstract public boolean isForeignKeyException(SQLException ex) throws 1071 SQLException; 1072 1073 abstract public PreparedStatement makePrimaryPreperedStatement(Connection pub_sub_Connection, String[] 1074 primaryColumns, String shadowTable, String local_pub_sub_name) throws 1075 SQLException, RepException; 1076 1077 public String getIgnoredColumns_Table() { 1078 return ignoredColumns_Table; 1079 } 1080 1081 public String getTrackReplicationTablesUpdation_Table() { 1082 return trackReplicationTablesUpdation_Table; 1083 } 1084 1085 public String getTrackPrimayKeyUpdation_Table() { 1086 return trackPrimaryKeyUpdation_Table; 1087 } 1088 1089 abstract protected void createIgnoredColumnsTable(String pubName) throws SQLException, 1090 RepException; 1091 abstract protected void createTrackReplicationTablesUpdationTable(String pubSubName) throws 1092 RepException, SQLException; 1093 abstract protected void createTriggerForTrackReplicationTablesUpdationTable(String 1094 pubSubName) throws RepException, SQLException ; 1095 public Object getMinValOfSyncIdTodeleteRecordsFromShadowTable(String tableName,Statement stmt) throws SQLException { 1096 ResultSet rs =null; 1097 // selecting min of syncid or concideredId from bookmarks table for one table 1098 try { 1099 StringBuffer query = new StringBuffer(); 1100 query.append("Select case when min(").append(RepConstants. 1101 bookmark_lastSyncId4).append(")< min(").append( 1102 RepConstants. 1103 bookmark_ConisderedId5).append(" )then min( ").append( 1104 RepConstants. 1105 bookmark_lastSyncId4).append(" ) else min( ").append( 1106 RepConstants. 1107 bookmark_ConisderedId5).append(") end from ").append( 1108 getBookMarkTableName()).append(" where ").append( 1109 RepConstants. 1110 bookmark_TableName3).append(" = '").append( tableName).append("'"); 1111 // System.out.println("AbstractDBHandler.deleteRecordsFromShadowTable=::"+query.toString()); 1112 rs = stmt.executeQuery(query.toString()); 1113 rs.next(); 1114 return rs.getObject(1); 1115 }finally{ 1116 if(rs!=null) 1117 try { 1118 rs.close(); 1119 } 1120 catch (SQLException ex) { 1121 } 1122 } 1123 } 1124 1125 1126 abstract public PreparedStatement makePrimaryPreperedStatementBackwardTraversing(String[] primaryColumns,long lastId,String local_pub_sub_name,String shadowTable) throws SQLException,RepException ; 1127 1128 String[] addPrefixWithColumnName(String[] columnNames0, String prefix) { 1129 String[] columnNames = new String[columnNames0.length]; 1130 for (int i = 0; i < columnNames.length; i++) { 1131 columnNames[i] = prefix+columnNames0[i]; 1132 } 1133 return columnNames; 1134 } 1135 1136 }

