1 22 package org.jboss.ejb.plugins.cmp.jdbc; 23 24 import java.sql.Connection ; 25 import java.sql.Statement ; 26 import java.util.Collection ; 27 import java.util.Iterator ; 28 import java.util.ArrayList ; 29 import java.util.HashSet ; 30 import java.util.List ; 31 import java.util.Set ; 32 import javax.sql.DataSource ; 33 import javax.transaction.Transaction ; 34 import javax.transaction.TransactionManager ; 35 36 import org.jboss.deployment.DeploymentException; 37 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCFieldBridge; 38 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractCMRFieldBridge; 39 import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCAbstractEntityBridge; 40 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData; 41 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationMetaData; 42 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCFunctionMappingMetaData; 43 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCRelationshipRoleMetaData; 44 import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCCMPFieldMetaData; 45 import org.jboss.ejb.plugins.cmp.bridge.EntityBridge; 46 import org.jboss.logging.Logger; 47 48 62 public final class JDBCStartCommand 63 { 64 private static final String IDX_POSTFIX = "_idx"; 65 private static final String COULDNT_SUSPEND = "Could not suspend current transaction before "; 66 private static final String COULDNT_REATTACH = "Could not reattach original transaction after "; 67 private final static Object CREATED_TABLES_KEY = new Object (); 68 private final JDBCEntityPersistenceStore manager; 69 private final JDBCAbstractEntityBridge entity; 70 private final JDBCEntityMetaData entityMetaData; 71 private final Logger log; 72 private static int idxCount = 0; 73 74 public JDBCStartCommand(JDBCEntityPersistenceStore manager) 75 { 76 this.manager = manager; 77 entity = manager.getEntityBridge(); 78 entityMetaData = manager.getMetaData(); 79 80 log = Logger.getLogger(this.getClass().getName() + 82 "." + 83 manager.getMetaData().getName()); 84 85 Set tables = (Set ) manager.getApplicationData(CREATED_TABLES_KEY); 87 if(tables == null) 88 { 89 manager.putApplicationData(CREATED_TABLES_KEY, new HashSet ()); 90 } 91 } 92 93 public void execute() throws DeploymentException 94 { 95 Set existedTables = getExistedTables(manager); 96 97 boolean tableExisted = SQLUtil.tableExists(entity.getQualifiedTableName(), entity.getDataSource()); 98 if(tableExisted) 99 { 100 existedTables.add(entity.getEntityName()); 101 } 102 103 if(tableExisted) 104 { 105 if(entityMetaData.getAlterTable()) 106 { 107 SQLUtil.OldColumns oldColumns = SQLUtil.getOldColumns(entity.getQualifiedTableName(), entity.getDataSource()); 108 ArrayList oldNames = oldColumns.getColumnNames(); 109 ArrayList oldTypes = oldColumns.getTypeNames(); 110 ArrayList oldSizes = oldColumns.getColumnSizes(); 111 SQLUtil.OldIndexes oldIndexes = null; 112 ArrayList newNames = new ArrayList (); 113 JDBCFieldBridge fields[] = entity.getTableFields(); 114 String tableName = entity.getQualifiedTableName(); 115 for(int i = 0; i < fields.length; i++) 116 { 117 JDBCFieldBridge field = fields[i]; 118 JDBCType jdbcType = field.getJDBCType(); 119 String [] columnNames = jdbcType.getColumnNames(); 120 String [] sqlTypes = jdbcType.getSQLTypes(); 121 boolean[] notNull = jdbcType.getNotNull(); 122 123 for(int j = 0; j < columnNames.length; j++) 124 { 125 String name = columnNames[j]; 126 String ucName = name.toUpperCase(); 127 128 newNames.add( ucName ); 129 130 int oldIndex = oldNames.indexOf( ucName ); 131 if(oldIndex == -1) 132 { 133 StringBuffer buf = new StringBuffer ( sqlTypes[j] ); 135 if( notNull[j] ) 136 { 137 buf.append(SQLUtil.NOT).append(SQLUtil.NULL); 138 } 139 alterTable(entity.getDataSource(), 140 entityMetaData.getTypeMapping().getAddColumnTemplate(), 141 tableName, name, buf.toString()); 142 } 143 else 144 { 145 String type = (String ) oldTypes.get(oldIndex); 148 if(type.equals("CHAR") || type.equals("VARCHAR")) 149 { 150 try 151 { 152 String l = sqlTypes[j]; 154 l = l.substring(l.indexOf('(') + 1, l.length() - 1); 155 Integer oldLength = (Integer ) oldSizes.get(oldIndex); 156 if(Integer.parseInt(l) > oldLength.intValue()) 157 { 158 alterTable(entity.getDataSource(), 159 entityMetaData.getTypeMapping().getAlterColumnTemplate(), 160 tableName, name, sqlTypes[j] ); 161 } 162 } 163 catch(Exception e) 164 { 165 log.warn("EXCEPTION ALTER :" + e.toString()); 166 } 167 } 168 } 169 } 170 171 JDBCCMPFieldMetaData fieldMD = entity.getMetaData().getCMPFieldByName(field.getFieldName()); 173 if(fieldMD != null && fieldMD.isIndexed()) 174 { 175 if(oldIndexes == null) 176 { 177 oldIndexes = SQLUtil.getOldIndexes(entity.getQualifiedTableName(), entity.getDataSource()); 178 idxCount = oldIndexes.getIndexNames().size(); 179 } 180 if(!hasIndex(oldIndexes, field)) 181 { 182 createCMPIndex( entity.getDataSource(), field, oldIndexes.getIndexNames() ); 183 } 184 185 } 186 } 188 Iterator it = oldNames.iterator(); 190 while(it.hasNext()) 191 { 192 String name = (String ) (it.next()); 193 if(!newNames.contains(name)) 194 { 195 alterTable(entity.getDataSource(), 196 entityMetaData.getTypeMapping().getDropColumnTemplate(), 197 tableName, name, ""); 198 } 199 } 200 201 } 202 } 203 204 Set createdTables = getCreatedTables(manager); 206 207 if(entityMetaData.getCreateTable() && !createdTables.contains(entity.getEntityName())) 208 { 209 DataSource dataSource = entity.getDataSource(); 210 createTable(dataSource, entity.getQualifiedTableName(), getEntityCreateTableSQL(dataSource)); 211 212 if(!tableExisted) 214 { 215 createCMPIndices( dataSource, 216 SQLUtil.getOldIndexes( entity.getQualifiedTableName(), 217 entity.getDataSource() ).getIndexNames() ); 218 } 219 else 220 { 221 if(log.isDebugEnabled()) 222 { 223 log.debug("Indices for table " + entity.getQualifiedTableName() + "not created as table existed"); 224 } 225 } 226 227 228 if(!tableExisted) 230 { 231 issuePostCreateSQL(dataSource, 232 entity.getMetaData().getDefaultTablePostCreateCmd(), 233 entity.getQualifiedTableName()); 234 } 235 236 createdTables.add(entity.getEntityName()); 237 } 238 else 239 { 240 log.debug("Table not create as requested: " + entity.getQualifiedTableName()); 241 } 242 243 JDBCAbstractCMRFieldBridge[] cmrFields = entity.getCMRFields(); 245 for(int i = 0; i < cmrFields.length; ++i) 246 { 247 JDBCAbstractCMRFieldBridge cmrField = cmrFields[i]; 248 JDBCRelationMetaData relationMetaData = cmrField.getMetaData().getRelationMetaData(); 249 250 final EntityBridge relatedEntity = cmrField.getRelatedEntity(); 252 if(relationMetaData.isTableMappingStyle() && createdTables.contains(relatedEntity.getEntityName())) 253 { 254 DataSource dataSource = relationMetaData.getDataSource(); 255 256 boolean relTableExisted = SQLUtil.tableExists(cmrField.getQualifiedTableName(), entity.getDataSource()); 257 258 if(relTableExisted) 259 { 260 if(relationMetaData.getAlterTable()) 261 { 262 ArrayList oldNames = SQLUtil.getOldColumns(cmrField.getQualifiedTableName(), dataSource).getColumnNames(); 263 ArrayList newNames = new ArrayList (); 264 JDBCFieldBridge[] leftKeys = cmrField.getTableKeyFields(); 265 JDBCFieldBridge[] rightKeys = cmrField.getRelatedCMRField().getTableKeyFields(); 266 JDBCFieldBridge[] fields = new JDBCFieldBridge[leftKeys.length + rightKeys.length]; 267 System.arraycopy(leftKeys, 0, fields, 0, leftKeys.length); 268 System.arraycopy(rightKeys, 0, fields, leftKeys.length, rightKeys.length); 269 271 boolean different = false; 272 for(int j = 0; j < fields.length; j++) 273 { 274 JDBCFieldBridge field = fields[j]; 275 276 String name = field.getJDBCType().getColumnNames()[0].toUpperCase(); 277 newNames.add(name); 278 279 if(!oldNames.contains(name)) 280 { 281 different = true; 282 break; 283 } 284 } 286 if(!different) 287 { 288 Iterator it = oldNames.iterator(); 289 while(it.hasNext()) 290 { 291 String name = (String ) (it.next()); 292 if(!newNames.contains(name)) 293 { 294 different = true; 295 break; 296 } 297 } 298 } 299 300 if(different) 301 { 302 log.error("CMR table structure is incorrect for " + cmrField.getQualifiedTableName()); 304 } 306 307 } 309 } 311 if(relationMetaData.isTableMappingStyle() && !relationMetaData.isTableCreated()) 313 { 314 if(relationMetaData.getCreateTable()) 315 { 316 createTable(dataSource, cmrField.getQualifiedTableName(), 317 getRelationCreateTableSQL(cmrField, dataSource)); 318 } 319 else 320 { 321 log.debug("Relation table not created as requested: " + cmrField.getQualifiedTableName()); 322 } 323 createCMRIndex(dataSource, cmrField); 325 326 if(relationMetaData.getCreateTable()) 327 { 328 issuePostCreateSQL(dataSource, 329 relationMetaData.getDefaultTablePostCreateCmd(), 330 cmrField.getQualifiedTableName()); 331 } 332 } 333 } 334 } 335 } 336 337 public void addForeignKeyConstraints() throws DeploymentException 338 { 339 Set createdTables = getCreatedTables(manager); 341 342 JDBCAbstractCMRFieldBridge[] cmrFields = entity.getCMRFields(); 343 for(int i = 0; i < cmrFields.length; ++i) 344 { 345 JDBCAbstractCMRFieldBridge cmrField = cmrFields[i]; 346 JDBCRelationMetaData relationMetaData = cmrField.getMetaData().getRelationMetaData(); 347 348 final EntityBridge relatedEntity = cmrField.getRelatedEntity(); 350 351 if(relationMetaData.isForeignKeyMappingStyle() && createdTables.contains(relatedEntity.getEntityName())) 355 { 356 createCMRIndex(((JDBCAbstractEntityBridge)relatedEntity).getDataSource(), cmrField); 357 } 358 359 addForeignKeyConstraint(cmrField); 361 } 362 } 363 364 public static Set getCreatedTables(JDBCEntityPersistenceStore manager) 365 { 366 final String key = "CREATED_TABLES"; 367 Set createdTables = (Set ) manager.getApplicationData(key); 368 if(createdTables == null) 369 { 370 createdTables = new HashSet (); 371 manager.putApplicationData(key, createdTables); 372 } 373 return createdTables; 374 } 375 376 public static Set getExistedTables(JDBCEntityPersistenceStore manager) 377 { 378 final String key = "EXISTED_TABLES"; 379 Set existedTables = (Set ) manager.getApplicationData(key); 380 if(existedTables == null) 381 { 382 existedTables = new HashSet (); 383 manager.putApplicationData(key, existedTables); 384 } 385 return existedTables; 386 } 387 388 395 private boolean hasIndex(SQLUtil.OldIndexes oldIndexes, JDBCFieldBridge field) 396 { 397 JDBCType jdbcType = field.getJDBCType(); 398 String [] columns = jdbcType.getColumnNames(); 399 ArrayList idxNames = oldIndexes.getIndexNames(); 400 ArrayList idxColumns = oldIndexes.getColumnNames(); 401 402 String indexName = null; 404 for(int i = 0; i < columns.length; ++i) 405 { 406 String column = columns[i]; 407 int index = columnIndex(idxColumns, column); 408 if(index == -1) 409 { 410 return false; 411 } 412 413 if(indexName == null) 414 { 415 indexName = (String )idxNames.get(index); 416 } 417 else if(!indexName.equals(idxNames.get(index))) 418 { 419 return false; 420 } 421 } 422 423 return true; 424 476 } 477 478 private int columnIndex(ArrayList idxColumns, String column) 479 { 480 for(int j = 0; j < idxColumns.size(); ++j) 481 { 482 String idxColumn = (String )idxColumns.get(j); 483 if(idxColumn.charAt(0) == '\"' && 484 idxColumn.charAt(idxColumn.charAt(idxColumn.length() - 1)) == '\"') 485 { 486 idxColumn = idxColumn.substring(1, idxColumn.length() - 1); 487 } 488 489 if(idxColumn.equalsIgnoreCase(column)) 490 { 491 return j; 492 } 493 } 494 return -1; 495 } 496 497 private void alterTable(DataSource dataSource, JDBCFunctionMappingMetaData mapping, String tableName, String fieldName, String fieldStructure) 498 throws DeploymentException 499 { 500 StringBuffer sqlBuf = new StringBuffer (); 501 mapping.getFunctionSql( new String []{tableName, fieldName, fieldStructure}, sqlBuf ); 502 String sql = sqlBuf.toString(); 503 504 log.warn( sql ); 505 506 TransactionManager tm = manager.getContainer().getTransactionManager(); 508 Transaction oldTransaction; 509 try 510 { 511 oldTransaction = tm.suspend(); 512 } 513 catch(Exception e) 514 { 515 throw new DeploymentException(COULDNT_SUSPEND + " alter table.", e); 516 } 517 518 try 519 { 520 Connection con = null; 521 Statement statement = null; 522 try 523 { 524 con = dataSource.getConnection(); 525 statement = con.createStatement(); 526 statement.executeUpdate(sql); 527 } 528 finally 529 { 530 JDBCUtil.safeClose(statement); 533 JDBCUtil.safeClose(con); 534 } 535 } 536 catch(Exception e) 537 { 538 log.error("Could not alter table " + tableName + ": " + e.getMessage()); 539 throw new DeploymentException("Error while alter table " + tableName + " " + sql, e); 540 } 541 finally 542 { 543 try 544 { 545 if(oldTransaction != null) 547 { 548 tm.resume(oldTransaction); 549 } 550 } 551 catch(Exception e) 552 { 553 throw new DeploymentException(COULDNT_REATTACH + "alter table"); 554 } 555 } 556 557 if ( log.isDebugEnabled() ) 559 log.debug("Table altered successfully."); 560 } 561 562 private void createTable(DataSource dataSource, String tableName, String sql) 563 throws DeploymentException 564 { 565 if(SQLUtil.tableExists(tableName, dataSource)) 567 { 568 log.debug("Table '" + tableName + "' already exists"); 569 return; 570 } 571 572 574 TransactionManager tm = manager.getContainer().getTransactionManager(); 576 Transaction oldTransaction; 577 try 578 { 579 oldTransaction = tm.suspend(); 580 } 581 catch(Exception e) 582 { 583 throw new DeploymentException(COULDNT_SUSPEND + "creating table.", e); 584 } 585 586 try 587 { 588 Connection con = null; 589 Statement statement = null; 590 try 591 { 592 if(log.isDebugEnabled()) 594 { 595 log.debug("Executing SQL: " + sql); 596 } 597 598 con = dataSource.getConnection(); 599 statement = con.createStatement(); 600 statement.executeUpdate(sql); 601 } 602 finally 603 { 604 JDBCUtil.safeClose(statement); 607 JDBCUtil.safeClose(con); 608 } 609 } 610 catch(Exception e) 611 { 612 log.debug("Could not create table " + tableName); 613 throw new DeploymentException("Error while creating table " + tableName, e); 614 } 615 finally 616 { 617 try 618 { 619 if(oldTransaction != null) 621 { 622 tm.resume(oldTransaction); 623 } 624 } 625 catch(Exception e) 626 { 627 throw new DeploymentException(COULDNT_REATTACH + "create table"); 628 } 629 } 630 631 Set createdTables = (Set ) manager.getApplicationData(CREATED_TABLES_KEY); 633 createdTables.add(tableName); 634 } 635 636 645 private void createIndex(DataSource dataSource, String tableName, String indexName, String sql) 646 throws DeploymentException 647 { 648 TransactionManager tm = manager.getContainer().getTransactionManager(); 652 Transaction oldTransaction; 653 try 654 { 655 oldTransaction = tm.suspend(); 656 } 657 catch(Exception e) 658 { 659 throw new DeploymentException(COULDNT_SUSPEND + "creating index.", e); 660 } 661 662 try 663 { 664 Connection con = null; 665 Statement statement = null; 666 try 667 { 668 if(log.isDebugEnabled()) 670 { 671 log.debug("Executing SQL: " + sql); 672 } 673 con = dataSource.getConnection(); 674 statement = con.createStatement(); 675 statement.executeUpdate(sql); 676 } 677 finally 678 { 679 JDBCUtil.safeClose(statement); 682 JDBCUtil.safeClose(con); 683 } 684 } 685 catch(Exception e) 686 { 687 log.debug("Could not create index " + indexName + "on table" + tableName); 688 throw new DeploymentException("Error while creating table", e); 689 } 690 finally 691 { 692 try 693 { 694 if(oldTransaction != null) 696 { 697 tm.resume(oldTransaction); 698 } 699 } 700 catch(Exception e) 701 { 702 throw new DeploymentException(COULDNT_REATTACH + "create index"); 703 } 704 } 705 } 706 707 708 715 private void issuePostCreateSQL(DataSource dataSource, List sql, String table) 716 throws DeploymentException 717 { 718 if(sql == null) 719 { log.trace("issuePostCreateSQL: sql is null"); 721 return; 722 } 723 724 log.debug("issuePostCreateSQL::sql: " + sql.toString() + " on table " + table); 725 726 TransactionManager tm = manager.getContainer().getTransactionManager(); 727 Transaction oldTransaction; 728 729 try 730 { 731 oldTransaction = tm.suspend(); 732 } 733 catch(Exception e) 734 { 735 throw new DeploymentException(COULDNT_SUSPEND + "sending sql command.", e); 736 } 737 738 String currentCmd = ""; 739 740 try 741 { 742 Connection con = null; 743 Statement statement = null; 744 try 745 { 746 con = dataSource.getConnection(); 747 statement = con.createStatement(); 748 749 for(int i = 0; i < sql.size(); i++) 751 { 752 currentCmd = (String ) sql.get(i); 753 756 currentCmd = replaceTable(currentCmd, table); 757 currentCmd = replaceIndexCounter(currentCmd); 758 log.debug("Executing SQL: " + currentCmd); 759 statement.executeUpdate(currentCmd); 760 } 761 } 762 finally 763 { 764 JDBCUtil.safeClose(statement); 767 JDBCUtil.safeClose(con); 768 } 769 } 770 catch(Exception e) 771 { 772 log.warn("Issuing sql " + currentCmd + " failed: " + e.toString()); 773 throw new DeploymentException("Error while issuing sql in post-table-create", e); 774 } 775 finally 776 { 777 try 778 { 779 if(oldTransaction != null) 781 { 782 tm.resume(oldTransaction); 783 } 784 } 785 catch(Exception e) 786 { 787 throw new DeploymentException(COULDNT_REATTACH + "create index"); 788 } 789 } 790 791 log.debug("Issued SQL " + sql + " successfully."); 793 } 794 795 private String getEntityCreateTableSQL(DataSource dataSource) 796 throws DeploymentException 797 { 798 StringBuffer sql = new StringBuffer (); 799 sql.append(SQLUtil.CREATE_TABLE).append(entity.getQualifiedTableName()).append(" ("); 800 801 boolean comma = false; 803 JDBCFieldBridge[] fields = entity.getTableFields(); 804 for(int i = 0; i < fields.length; ++i) 805 { 806 JDBCFieldBridge field = fields[i]; 807 JDBCType type = field.getJDBCType(); 808 if(comma) 809 { 810 sql.append(SQLUtil.COMMA); 811 } 812 else 813 { 814 comma = true; 815 } 816 addField(type, sql); 817 } 818 819 if(entityMetaData.hasPrimaryKeyConstraint()) 821 { 822 JDBCFunctionMappingMetaData pkConstraint = manager.getMetaData().getTypeMapping().getPkConstraintTemplate(); 823 if(pkConstraint == null) 824 { 825 throw new IllegalStateException ("Primary key constraint is " + 826 "not allowed for this type of data source"); 827 } 828 829 String defTableName = entity.getManager().getMetaData().getDefaultTableName(); 830 String name = "pk_" + SQLUtil.unquote(defTableName, dataSource); 831 name = SQLUtil.fixConstraintName(name, dataSource); 832 String [] args = new String []{ 833 name, 834 SQLUtil.getColumnNamesClause(entity.getPrimaryKeyFields(), new StringBuffer (100)).toString() 835 }; 836 sql.append(SQLUtil.COMMA); 837 pkConstraint.getFunctionSql(args, sql); 838 } 839 840 return sql.append(')').toString(); 841 } 842 843 850 private void createCMPIndices(DataSource dataSource, ArrayList indexNames) 851 throws DeploymentException 852 { 853 JDBCFieldBridge[] cmpFields = entity.getTableFields(); 855 for(int i = 0; i < cmpFields.length; ++i) 856 { 857 JDBCFieldBridge field = cmpFields[i]; 858 JDBCCMPFieldMetaData fieldMD = entity.getMetaData().getCMPFieldByName(field.getFieldName()); 859 860 if(fieldMD != null && fieldMD.isIndexed()) 861 { 862 createCMPIndex(dataSource, field, indexNames); 863 } 864 } 865 866 final JDBCAbstractCMRFieldBridge[] cmrFields = entity.getCMRFields(); 867 if(cmrFields != null) 868 { 869 for(int i = 0; i < cmrFields.length; ++i) 870 { 871 JDBCAbstractCMRFieldBridge cmrField = cmrFields[i]; 872 if(cmrField.getRelatedCMRField().getMetaData().isIndexed()) 873 { 874 final JDBCFieldBridge[] fkFields = cmrField.getForeignKeyFields(); 875 if(fkFields != null) 876 { 877 for(int fkInd = 0; fkInd < fkFields.length; ++fkInd) 878 { 879 createCMPIndex(dataSource, fkFields[fkInd], indexNames); 880 } 881 } 882 } 883 } 884 } 885 } 886 887 894 private void createCMPIndex(DataSource dataSource, JDBCFieldBridge field, ArrayList indexNames) 895 throws DeploymentException 896 { 897 StringBuffer sql; 898 log.debug("Creating index for field " + field.getFieldName()); 899 sql = new StringBuffer (); 900 sql.append(SQLUtil.CREATE_INDEX); 901 String indexName; 902 boolean indexExists; 903 do 904 { 905 indexName = entity.getQualifiedTableName() + IDX_POSTFIX + idxCount; 906 idxCount++; 907 indexExists = false; 908 if ( indexNames != null ) 909 { 910 for ( int i = 0 ; i < indexNames.size() && !indexExists ; i++ ) 911 { 912 indexExists = indexName.equalsIgnoreCase( ( (String ) indexNames.get( i ) ) ); 913 } 914 } 915 } 916 while ( indexExists ); 917 918 sql.append( indexName ); 919 sql.append(SQLUtil.ON); 920 sql.append(entity.getQualifiedTableName() + " ("); 921 SQLUtil.getColumnNamesClause(field, sql); 922 sql.append(")"); 923 924 createIndex(dataSource, entity.getQualifiedTableName(), indexName, sql.toString()); 925 } 926 927 private void createCMRIndex(DataSource dataSource, JDBCAbstractCMRFieldBridge field) 928 throws DeploymentException 929 { 930 JDBCRelationMetaData rmd; 931 String tableName; 932 933 rmd = field.getMetaData().getRelationMetaData(); 934 935 if(rmd.isTableMappingStyle()) 936 { 937 tableName = rmd.getDefaultTableName(); 938 createFKIndex(rmd.getLeftRelationshipRole(), dataSource, tableName); 939 createFKIndex(rmd.getRightRelationshipRole(), dataSource, tableName); 940 } 941 else if(field.hasForeignKey()) 942 { 943 tableName = field.getEntity().getQualifiedTableName(); 944 createFKIndex(field.getRelatedCMRField().getMetaData(), dataSource, tableName); 945 } 946 } 947 948 private void createFKIndex(JDBCRelationshipRoleMetaData metadata, DataSource dataSource, String tableName) 949 throws DeploymentException 950 { 951 Collection kfl = metadata.getKeyFields(); 952 Iterator it = kfl.iterator(); 953 while(it.hasNext()) 954 { 955 JDBCCMPFieldMetaData fi = (JDBCCMPFieldMetaData) it.next(); 956 if(metadata.isIndexed()) 957 { 958 createIndex(dataSource, tableName, fi.getFieldName(), createIndexSQL(fi, tableName)); 959 idxCount++; 960 } 961 } 962 } 963 964 private static String createIndexSQL(JDBCCMPFieldMetaData fi, String tableName) 965 { 966 StringBuffer sql = new StringBuffer (); 967 sql.append(SQLUtil.CREATE_INDEX); 968 sql.append(fi.getColumnName() + IDX_POSTFIX + idxCount); 969 sql.append(SQLUtil.ON); 970 sql.append(tableName + " ("); 971 sql.append(fi.getColumnName()); 972 sql.append(')'); 973 return sql.toString(); 974 } 975 976 private void addField(JDBCType type, StringBuffer sqlBuffer) throws DeploymentException 977 { 978 if(type.getAutoIncrement()[0]) 980 { 981 String columnClause = SQLUtil.getCreateTableColumnsClause(type); 982 JDBCFunctionMappingMetaData autoIncrement = 983 manager.getMetaData().getTypeMapping().getAutoIncrementTemplate(); 984 if(autoIncrement == null) 985 { 986 throw new IllegalStateException ("auto-increment template not found"); 987 } 988 String [] args = new String []{columnClause}; 989 autoIncrement.getFunctionSql(args, sqlBuffer); 990 } 991 else 992 { 993 sqlBuffer.append(SQLUtil.getCreateTableColumnsClause(type)); 994 } 995 } 996 997 private String getRelationCreateTableSQL(JDBCAbstractCMRFieldBridge cmrField, 998 DataSource dataSource) 999 throws DeploymentException 1000 { 1001 JDBCFieldBridge[] leftKeys = cmrField.getTableKeyFields(); 1002 JDBCFieldBridge[] rightKeys = cmrField.getRelatedCMRField().getTableKeyFields(); 1003 JDBCFieldBridge[] fieldsArr = new JDBCFieldBridge[leftKeys.length + rightKeys.length]; 1004 System.arraycopy(leftKeys, 0, fieldsArr, 0, leftKeys.length); 1005 System.arraycopy(rightKeys, 0, fieldsArr, leftKeys.length, rightKeys.length); 1006 1007 StringBuffer sql = new StringBuffer (); 1008 sql.append(SQLUtil.CREATE_TABLE).append(cmrField.getQualifiedTableName()) 1009 .append(" (") 1010 .append(SQLUtil.getCreateTableColumnsClause(fieldsArr)); 1012 1013 final JDBCRelationMetaData relationMetaData = cmrField.getMetaData().getRelationMetaData(); 1015 if(relationMetaData.hasPrimaryKeyConstraint()) 1016 { 1017 JDBCFunctionMappingMetaData pkConstraint = 1018 manager.getMetaData().getTypeMapping().getPkConstraintTemplate(); 1019 if(pkConstraint == null) 1020 { 1021 throw new IllegalStateException ("Primary key constraint is not allowed for this type of data store"); 1022 } 1023 1024 String name = "pk_" + relationMetaData.getDefaultTableName(); 1025 name = SQLUtil.fixConstraintName(name, dataSource); 1026 String [] args = new String []{ 1027 name, 1028 SQLUtil.getColumnNamesClause(fieldsArr, new StringBuffer (100).toString(), new StringBuffer ()).toString() 1029 }; 1030 sql.append(SQLUtil.COMMA); 1031 pkConstraint.getFunctionSql(args, sql); 1032 } 1033 sql.append(')'); 1034 return sql.toString(); 1035 } 1036 1037 private void addForeignKeyConstraint(JDBCAbstractCMRFieldBridge cmrField) 1038 throws DeploymentException 1039 { 1040 JDBCRelationshipRoleMetaData metaData = cmrField.getMetaData(); 1041 if(metaData.hasForeignKeyConstraint()) 1042 { 1043 if(metaData.getRelationMetaData().isTableMappingStyle()) 1044 { 1045 addForeignKeyConstraint(metaData.getRelationMetaData().getDataSource(), 1046 cmrField.getQualifiedTableName(), 1047 cmrField.getFieldName(), 1048 cmrField.getTableKeyFields(), 1049 cmrField.getEntity().getQualifiedTableName(), 1050 cmrField.getEntity().getPrimaryKeyFields()); 1051 1052 } 1053 else if(cmrField.hasForeignKey()) 1054 { 1055 JDBCAbstractEntityBridge relatedEntity = (JDBCAbstractEntityBridge) cmrField.getRelatedEntity(); 1056 addForeignKeyConstraint(cmrField.getEntity().getDataSource(), 1057 cmrField.getEntity().getQualifiedTableName(), 1058 cmrField.getFieldName(), 1059 cmrField.getForeignKeyFields(), 1060 relatedEntity.getQualifiedTableName(), 1061 relatedEntity.getPrimaryKeyFields()); 1062 } 1063 } 1064 else 1065 { 1066 log.debug("Foreign key constraint not added as requested: relationshipRolename=" + metaData.getRelationshipRoleName()); 1067 } 1068 } 1069 1070 private void addForeignKeyConstraint(DataSource dataSource, 1071 String tableName, 1072 String cmrFieldName, 1073 JDBCFieldBridge[] fields, 1074 String referencesTableName, 1075 JDBCFieldBridge[] referencesFields) throws DeploymentException 1076 { 1077 Set createdTables = (Set ) manager.getApplicationData(CREATED_TABLES_KEY); 1079 if(!createdTables.contains(tableName)) 1080 { 1081 return; 1082 } 1083 1084 JDBCFunctionMappingMetaData fkConstraint = manager.getMetaData().getTypeMapping().getFkConstraintTemplate(); 1085 if(fkConstraint == null) 1086 { 1087 throw new IllegalStateException ("Foreign key constraint is not allowed for this type of datastore"); 1088 } 1089 String a = SQLUtil.getColumnNamesClause(fields, new StringBuffer (50)).toString(); 1090 String b = SQLUtil.getColumnNamesClause(referencesFields, new StringBuffer (50)).toString(); 1091 1092 String [] args = new String []{ 1093 tableName, 1094 SQLUtil.fixConstraintName("fk_" + tableName + "_" + cmrFieldName, dataSource), 1095 a, 1096 referencesTableName, 1097 b}; 1098 1099 String sql = fkConstraint.getFunctionSql(args, new StringBuffer (100)).toString(); 1100 1101 TransactionManager tm = manager.getContainer().getTransactionManager(); 1104 Transaction oldTransaction; 1105 try 1106 { 1107 oldTransaction = tm.suspend(); 1108 } 1109 catch(Exception e) 1110 { 1111 throw new DeploymentException(COULDNT_SUSPEND + "alter table create foreign key.", e); 1112 } 1113 1114 try 1115 { 1116 Connection con = null; 1117 Statement statement = null; 1118 try 1119 { 1120 if(log.isDebugEnabled()) 1121 { 1122 log.debug("Executing SQL: " + sql); 1123 } 1124 con = dataSource.getConnection(); 1125 statement = con.createStatement(); 1126 statement.executeUpdate(sql); 1127 } 1128 finally 1129 { 1130 JDBCUtil.safeClose(statement); 1133 JDBCUtil.safeClose(con); 1134 } 1135 } 1136 catch(Exception e) 1137 { 1138 log.warn("Could not add foreign key constraint: table=" + tableName); 1139 throw new DeploymentException("Error while adding foreign key constraint", e); 1140 } 1141 finally 1142 { 1143 try 1144 { 1145 if(oldTransaction != null) 1147 { 1148 tm.resume(oldTransaction); 1149 } 1150 } 1151 catch(Exception e) 1152 { 1153 throw new DeploymentException(COULDNT_REATTACH + "create table"); 1154 } 1155 } 1156 } 1157 1158 1159 1166 private static String replaceTable(String in, String table) 1167 { 1168 int pos; 1169 1170 pos = in.indexOf("%%t"); 1171 if(pos == -1) 1173 { 1174 return in; 1175 } 1176 1177 String first = in.substring(0, pos); 1178 String last = in.substring(pos + 3); 1179 1180 return first + table + last; 1181 } 1182 1183 1189 private static String replaceIndexCounter(String in) 1190 { 1191 int pos; 1192 1193 pos = in.indexOf("%%n"); 1194 if(pos == -1) 1196 { 1197 return in; 1198 } 1199 1200 String first = in.substring(0, pos); 1201 String last = in.substring(pos + 3); 1202 idxCount++; 1203 return first + idxCount + last; 1204 } 1205} 1206 | Popular Tags |