1 22 23 package org.xquark.mapper.mapping; 24 25 import java.util.*; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.commons.logging.LogFactory; 29 import org.xml.sax.SAXException ; 30 import org.xquark.jdbc.typing.ColumnMetaData; 31 import org.xquark.mapper.dbms.AbstractConnection; 32 import org.xquark.schema.ElementDeclaration; 33 import org.xquark.schema.SchemaComponent; 34 import org.xquark.schema.Type; 35 36 43 class TableMappingImpl extends BaseTableMappingImpl 44 { 45 private static final String RCSRevision = "$Revision: 1.7 $"; 46 private static final String RCSName = "$Name: $"; 47 48 private static final short USE_PK = 0; 49 private static final short USE_KEYGEN = 1; 50 private static final short USE_ALL = 2; 51 52 private static Log log = LogFactory.getLog(TableMappingImpl.class); 53 54 55 56 57 private HashSet mappedElements = new HashSet(); 58 59 private HashSet endingElements = new HashSet(); 60 61 protected String selectStatement; 62 protected String updateStatement; 63 64 private short joinMode = -1; 65 66 67 private int keyGenColumnCount = 0; 68 private int selectColumnCount = 0; 69 private int fetchColumnCount = 0; 70 private int updateColumnCount = 0; 71 private int columnMappingCount = 0; private ColumnMappingImpl[] denseColumnMappingArray = null; 74 private int action; 75 private boolean clustered = false; private ColumnMappingImpl uoidColumn = null; private ColumnMappingImpl pathColumn = null; 79 private int batchSize; 81 private boolean userTablesOnly = false; 82 private boolean shared = false; 83 84 93 TableMappingImpl(RepositoryMapping colMapping, SchemaComponent comp, 94 String tableName, AbstractConnection conn, int action, boolean generate, 95 int batchSize, boolean userTablesOnly) throws SAXException 96 { 97 super(colMapping, comp, conn); 98 this.name = tableName; 99 this.userTablesOnly = userTablesOnly; 100 tableMetaData = colMapping.getTableMetaData(name, conn); 101 shared = comp instanceof Type; 102 103 if (!generate && tableMetaData == null) 105 throw new SAXException ("Table " + name + " does not exist in database."); 106 107 if (tableMetaData == null) 108 columnMappings = new ColumnMapping[20]; 110 else columnMappings = new ColumnMapping[tableMetaData.getColumnCount()]; 112 113 this.action = action; 114 this.batchSize = batchSize; 115 } 116 117 public int getBatchSize() { return batchSize;} 118 119 public int getOIDTableColumnCount() { return OIDColumnMappings.length + 2;} 120 121 public int getSelectColumnCount() { return selectColumnCount;} 122 123 public int getFetchColumnCount() { return fetchColumnCount;} 124 125 public int getKeyGenColumnCount() { return keyGenColumnCount;} 126 127 public int getUpdateColumnCount() { return updateColumnCount;} 128 129 public int getColumnMappingCount() { return columnMappingCount;} 130 131 public ColumnMapping[] getColumnMappings() { return denseColumnMappingArray;} 132 133 public int getAction() { return action;} 134 135 138 public boolean isClustered() { return clustered;} 139 140 143 public boolean isShared() { return shared;} 144 145 148 public int getPathIDIndex() 149 { 150 if (pathColumn != null) 151 return pathColumn.getColumnIndex(); 152 else 153 return 1; 154 } 155 156 159 public int getUOIDIndex() 160 { 161 if (uoidColumn != null) 162 return uoidColumn.getColumnIndex(); 163 else 164 return 0; 165 } 166 167 171 public String getPathIDColumnName() 172 { 173 if (pathColumn != null) 174 return pathColumn.getColumnName(); 175 else 176 return super.getPathIDColumnName(); 177 } 178 179 183 public String getUOIDColumnName() 184 { 185 if (uoidColumn != null) 186 return uoidColumn.getColumnName(); 187 else 188 return super.getUOIDColumnName(); 189 } 190 193 public boolean isTerminatedBy(ElementDeclaration decl) 194 { 195 return endingElements.contains(decl); 196 } 197 198 public String getOIDTableName() { return null;} 203 204 public String getOIDInsertStatement() { return null;} 206 207 public String getSelectStatement() { return selectStatement;} 208 209 public String getUpdateStatement() { return updateStatement;} 210 211 218 void addMappedChild(ElementDeclaration decl) 219 { 220 if (!mappedElements.contains(decl)) 221 mappedElements.add(decl); 222 } 223 224 229 void initialize(AbstractConnection conn) throws SAXException 230 { 231 initializeColumnMappings(); 232 checkMapping(); 233 initializeCluster(); 234 initializeStatements(conn); 235 initializeEndingElements(); 236 } 237 238 boolean isInitialized() { return primaryKeyColumnMappings != null;} 239 240 247 private void initializeColumnMappings() throws SAXException 248 { 249 if (getColumnMappingCount() == 0) 250 throw new SAXException ("Table mapping must specify at least one column mapping"); 251 252 253 int uoidColumnCount = 0; 254 255 if (keyColumnCount > 0) { 257 joinMode = USE_PK; 258 uoidColumnCount = keyColumnCount; 259 } 260 else if (keyGenColumnCount > 0) { 262 joinMode = USE_KEYGEN; 263 uoidColumnCount = keyColumnCount = keyGenColumnCount; 264 } 265 else { 267 joinMode = USE_ALL; 268 uoidColumnCount = getColumnCount(); 269 } 270 271 primaryKeyColumnMappings = new ColumnMapping[keyColumnCount]; 272 OIDColumnMappings = new ColumnMapping[uoidColumnCount]; 273 updateColumnMappings = new ColumnMapping[updateColumnCount]; 274 selectColumnMappings = new ColumnMapping[selectColumnCount]; 275 fetchColumnMappings = new ColumnMapping[fetchColumnCount]; 276 denseColumnMappingArray = new ColumnMappingImpl[columnMappingCount]; 277 278 int joinColumnCount = 2; int OIDcount = 0; 280 281 Iterator it = getColumnMappingIterator(); 282 while (it.hasNext()) 283 { 284 ColumnMappingImpl mapping = (ColumnMappingImpl)it.next(); 285 286 denseColumnMappingArray[mapping.getInsertColumnIndex()] = mapping; 287 288 switch (joinMode) 289 { 290 case USE_PK: 291 if (mapping.getKeyColumnIndex() != -1) 292 { 293 primaryKeyColumnMappings[mapping.getKeyColumnIndex()] = mapping; 294 mapping.setJoinColumnIndex(joinColumnCount++); 295 OIDColumnMappings[mapping.getKeyColumnIndex()] = mapping; 296 } 297 break; 298 case USE_KEYGEN: 299 if (mapping.getKeyGenColumnIndex() != -1) 300 { 301 primaryKeyColumnMappings[mapping.getKeyGenColumnIndex()] = mapping; 302 mapping.setJoinColumnIndex(joinColumnCount++); 303 OIDColumnMappings[mapping.getKeyGenColumnIndex()] = mapping; 304 } 305 break; 306 case USE_ALL: 307 mapping.setJoinColumnIndex(joinColumnCount++); 308 OIDColumnMappings[OIDcount++] = mapping; 309 break; 310 } 311 if (mapping.getSelectColumnIndex() != -1) 312 selectColumnMappings[mapping.getSelectColumnIndex()] = mapping; 313 314 if (mapping.getFetchColumnIndex() != -1) 315 fetchColumnMappings[mapping.getFetchColumnIndex()] = mapping; 316 317 if (mapping.getUpdateColumnIndex() != -1) updateColumnMappings[mapping.getUpdateColumnIndex()] = mapping; 319 } 320 } 321 322 326 private void checkMapping() throws SAXException 327 { 328 if ((action != INSERT) && (selectColumnCount == 0)) 330 throw new SAXException ("When using the SELECT, CHECK or UPDATE mode, there must be at least one 'select' column."); 331 332 if (getMetaData() != null) 334 { 335 if ((action == INSERT) || (action == CHECK)) 337 { 338 Iterator it = tableMetaData.getColumnsMetaData().iterator(); 339 while (it.hasNext()) 340 { 341 ColumnMetaData cmeta = (ColumnMetaData)it.next(); 342 ColumnMapping mapping = getColumnMapping(cmeta.getColumnName()); 343 344 if (mapping == null && !cmeta.isOptional()) 346 log.warn("Missing mapping specification for " + cmeta); 347 } 348 } 349 350 if (!userTablesOnly) 352 { 353 if (action == INSERT) 354 { 355 if (joinMode != USE_PK) { 357 Set keys = new HashSet(); 359 ColumnMappingImpl column; 360 361 for (int i = 0; i < denseColumnMappingArray.length; i++) 362 { 363 column = denseColumnMappingArray[i]; 364 if (column.isInJoin()) 365 keys.add(column.getMetaData()); 366 } 367 368 Iterator it = getMetaData().getUniqueConstraints().iterator(); 371 boolean matches = false; 372 373 while (it.hasNext() && !matches) 374 matches |= keys.containsAll((Collection)it.next()); 375 376 if (!matches) 378 throw new SAXException ("When using the INSERT mode, a relational UNIQUE constraint (or Primary Key) must be defined on key columns."); 379 } 380 } 381 else if (action != SELECT) { 383 HashSet inter = new HashSet(Arrays.asList(OIDColumnMappings)); 384 inter.retainAll(Arrays.asList(updateColumnMappings)); 385 if (!inter.isEmpty()) 387 throw new SAXException ("When using the CHECK or UPDATE mode, Primary Key columns cannot be updated. Check that attribute 'inSelect' is true for columns " + inter); 388 } 390 } 391 } 392 } 393 394 397 private void initializeCluster() throws SAXException 398 { 399 ColumnMappingImpl column; 400 boolean oid = false, root = false; 401 SystemVariableGenerator sysGen; 402 for (int i = 0; i < denseColumnMappingArray.length; i++) 403 { 404 column = denseColumnMappingArray[i]; 405 if (column.getGenerator() instanceof SystemVariableGenerator) 406 { 407 sysGen = (SystemVariableGenerator)column.getGenerator(); 408 if (sysGen.getType() == PATHID_CODE) pathColumn = column; 410 else if (sysGen.getType() == UOID_CODE) 411 uoidColumn = column; 412 } 413 } 414 if (userTablesOnly || ((action == INSERT) 415 && (uoidColumn != null) && (uoidColumn.getKeyGenColumnIndex() >= 0) 416 && (pathColumn != null) && (pathColumn.getKeyGenColumnIndex() >= 0))) 417 clustered = true; 418 } 419 420 423 void initializeStatements(AbstractConnection conn) 424 { 425 if (tableMetaData == null) 426 return; 427 StringBuffer lColumnList = new StringBuffer (), 428 lNamedColumnList = new StringBuffer (), 429 lWildcards = new StringBuffer (); 430 431 for (int i = 0; i < denseColumnMappingArray.length; i++) 433 { 434 ColumnMappingImpl mapping = denseColumnMappingArray[i]; 435 String columnName = mapping.getColumnName(); 436 if (conn.useDoubleQuotes4DDLNames()) 437 columnName = '"' + columnName + '"'; 438 if (lColumnList.length() > 0) 439 { 440 lColumnList.append(", "); 441 lNamedColumnList.append(", "); 442 lWildcards.append( ", "); 443 } 444 lColumnList.append(columnName); 445 lNamedColumnList.append("w."); 446 lNamedColumnList.append(columnName); 447 lWildcards.append("?"); 448 if (mapping.isInJoin()) 449 { 450 451 ColumnMetaData cmeta = mapping.getMetaData(); 452 String columnType = null; 453 if (cmeta.getColumnSize() > 0) 454 columnType = cmeta.getTypeCreationString(); 455 if (joinColumnList.length() > 0) 456 { 457 joinColumnList += ", "; 458 joinWildcards += ", "; 459 joinColumnTypes += ", "; 460 joinCondition += " AND "; 461 } 462 joinColumnList += columnName; 463 joinWildcards += "?"; 464 joinColumnTypes += columnName + " " + columnType; 465 if (mapping.getMinOccurs() > 0) joinCondition += "v."+columnName+"=w."+columnName; 467 else 468 joinCondition += "((v."+columnName+"=w."+columnName+") OR (v."+columnName+" IS NULL AND w."+columnName+" IS NULL))"; 469 } 470 } 471 columnList = lColumnList.toString(); 472 namedColumnList = lNamedColumnList.toString(); 473 wildcards = lWildcards.toString(); 474 475 lColumnList.setLength(0); 476 for (int i = 0; i < selectColumnMappings.length; i++) 477 { 478 if (i > 0) 479 lColumnList.append(" AND "); 480 if (conn.useDoubleQuotes4DDLNames()) 481 lColumnList.append('"'); 482 lColumnList.append(selectColumnMappings[i].getColumnName()); 483 if (conn.useDoubleQuotes4DDLNames()) 484 lColumnList.append('"'); 485 lColumnList.append(" = ?"); 486 } 487 String selectCondition = lColumnList.toString(); 488 489 lColumnList.setLength(0); 490 for (int i = 0; i < updateColumnMappings.length; i++) 491 { 492 if (i > 0) 493 lColumnList.append(", "); 494 if (conn.useDoubleQuotes4DDLNames()) 495 lColumnList.append('"'); 496 lColumnList.append(updateColumnMappings[i].getColumnName()); 497 if (conn.useDoubleQuotes4DDLNames()) 498 lColumnList.append('"'); 499 lColumnList.append(" = ?"); 500 } 501 String updateColumnList = lColumnList.toString(); 502 503 lColumnList.setLength(0); 504 for (int i = 0; i < fetchColumnMappings.length; i++) 505 { 506 if (i > 0) 507 lColumnList.append(", "); 508 if (conn.useDoubleQuotes4DDLNames()) 509 lColumnList.append('"'); 510 lColumnList.append(fetchColumnMappings[i].getColumnName()); 511 if (conn.useDoubleQuotes4DDLNames()) 512 lColumnList.append('"'); 513 } 514 String fetchColumnList = lColumnList.toString(); 515 516 String tableName = getTableName(); if (conn.useDoubleQuotes4DDLNames()) 519 tableName = '"' + tableName + '"'; 520 StringBuffer sql = new StringBuffer (); 521 sql.append("INSERT INTO "); 522 sql.append(tableName); 523 sql.append('('); 524 sql.append(columnList); 525 sql.append(") VALUES("); 526 sql.append(wildcards); 527 sql.append(')'); 528 insertStatement = sql.toString(); 529 if (selectCondition.length() > 0) 530 { 531 sql.setLength(0); 532 sql.append("SELECT "); 533 if (fetchColumnCount == 0) 534 sql.append('1'); 535 else 536 sql.append(fetchColumnList); 537 sql.append(" FROM "); 538 sql.append(tableName); 539 sql.append(" WHERE "); 540 sql.append(selectCondition); 541 selectStatement = sql.toString(); 542 if (updateColumnList.length() > 0) 543 { 544 sql.setLength(0); 545 sql.append("UPDATE "); 546 sql.append(tableName); 547 sql.append(" SET "); 548 sql.append(updateColumnList); 549 sql.append(" WHERE "); 550 sql.append(selectCondition); 551 updateStatement = sql.toString(); 552 } 553 } 554 } 555 556 557 void initializeEndingElements() {} 558 559 564 Collection initializeDependencies() throws SAXException 565 { 566 if (dependencies == null) 567 { 568 dependencies = new HashSet(); 569 for (int i = 0; i < denseColumnMappingArray.length; i++) 570 { 571 int tableIndex = denseColumnMappingArray[i].getTableRefIndex(); 572 if (tableIndex != -1) 573 { 574 TableMappingImpl tm = (TableMappingImpl)colMapping.getTableMapping(tableIndex); 575 dependencies.add(tm); 576 Collection dep = tm.getDependencies(); 577 if (dep == null) dep = tm.initializeDependencies(); 579 dependencies.addAll(dep); 580 } 581 } 582 if (dependencies.contains(this)) 583 throw new SAXException ("Circular integrity constraints between tables are not supported"); 584 } 585 return dependencies; 586 } 587 588 592 int register(ColumnMapping mapping) throws SAXException 593 { 594 if (!userTablesOnly) { 597 Iterator it = getColumnMappingIterator(); 598 ColumnMapping current = null; 599 while (it.hasNext()) 600 { 601 current = (ColumnMappingImpl)it.next(); 602 if (current.getColumnName().equalsIgnoreCase(mapping.getColumnName())) 603 throw new SAXException ("A column mapping has already been defined on column '" 604 + current.getColumnName() + "' for " + current.getSchemaComponent() + "."); 605 } 606 } 607 608 int index; 609 610 if (tableMetaData == null) { 613 if (getColumnMappingCount() == columnMappings.length) 615 { 616 ColumnMapping[] newArray = new ColumnMapping[columnMappings.length * 2]; 617 System.arraycopy(columnMappings, 0, newArray, 0, columnMappings.length); 618 columnMappings = newArray; 619 } 620 index = getColumnMappingCount(); 621 } 622 else 623 { 624 ColumnMetaData cMeta = mapping.getMetaData(); 626 if (cMeta.isLongType()) 627 batchSize = 1; 628 index = cMeta.getOrdinalPosition() - 1; 629 } 630 columnMappings[index] = mapping; 631 return index; } 633 634 int incrementColumnMappingCount() 635 { 636 return columnMappingCount++; 637 } 638 639 645 int incrementKeyColumnCount() 646 { 647 return keyColumnCount++; 648 } 649 650 655 int incrementSelectColumnCount() 656 { 657 return selectColumnCount++; 658 } 659 660 665 int incrementFetchColumnCount() 666 { 667 return fetchColumnCount++; 668 } 669 670 674 int incrementUpdateColumnCount() 675 { 676 return updateColumnCount++; 677 } 678 679 int incrementKeyGenColumnCount() 680 { 681 return keyGenColumnCount++; 682 } 683 684 } 685 | Popular Tags |