1 17 package org.apache.ws.jaxme.sqls.impl; 18 19 import java.io.Serializable ; 20 import java.sql.Connection ; 21 import java.sql.DatabaseMetaData ; 22 import java.sql.ResultSet ; 23 import java.sql.SQLException ; 24 import java.sql.Types ; 25 import java.util.ArrayList ; 26 import java.util.Iterator ; 27 import java.util.List ; 28 29 import org.apache.ws.jaxme.logging.Logger; 30 import org.apache.ws.jaxme.logging.LoggerAccess; 31 import org.apache.ws.jaxme.sqls.BinaryColumn; 32 import org.apache.ws.jaxme.sqls.Column; 33 import org.apache.ws.jaxme.sqls.DeleteStatement; 34 import org.apache.ws.jaxme.sqls.ForeignKey; 35 import org.apache.ws.jaxme.sqls.Index; 36 import org.apache.ws.jaxme.sqls.InsertStatement; 37 import org.apache.ws.jaxme.sqls.ObjectFactory; 38 import org.apache.ws.jaxme.sqls.SQLFactory; 39 import org.apache.ws.jaxme.sqls.SQLGenerator; 40 import org.apache.ws.jaxme.sqls.Schema; 41 import org.apache.ws.jaxme.sqls.SelectStatement; 42 import org.apache.ws.jaxme.sqls.StringColumn; 43 import org.apache.ws.jaxme.sqls.Table; 44 import org.apache.ws.jaxme.sqls.UpdateStatement; 45 46 47 51 public class SQLFactoryImpl implements SQLFactory { 52 private static final Logger logger = LoggerAccess.getLogger(SQLFactoryImpl.class); 53 54 56 public static class IdentImpl implements SQLFactory.Ident, Serializable { 57 private String name; 58 59 protected IdentImpl(String pName) { 60 if (pName == null) { 61 throw new NullPointerException ("An ident's string representation must not be null."); 62 } 63 name = pName; 64 } 65 66 public String getName() { 67 return name; 68 } 69 70 public String toString() { 71 return name; 72 } 73 74 public boolean equals(Object o) { 75 if (o == null || !(o instanceof SQLFactory.Ident)) { 76 return false; 77 } 78 return name.equalsIgnoreCase(((SQLFactory.Ident) o).getName()); 79 } 80 public int hashCode() { 81 return name.hashCode(); 82 } 83 } 84 85 private List schemas = new ArrayList (); 86 private Integer maxTableNameLength, maxSchemaNameLength, maxColumnNameLength; 87 private boolean tableNameCaseSensitive, schemaNameCaseSensitive, columnNameCaseSensitive; 88 private Schema defaultSchema; 89 private ObjectFactory objectFactory = newObjectFactory(); 90 91 93 public SQLFactoryImpl() { 94 } 95 96 protected ObjectFactory newObjectFactory() { 97 return new ObjectFactoryImpl(); 98 } 99 100 public ObjectFactory getObjectFactory() { 101 return objectFactory; 102 } 103 104 protected void setObjectFactory(ObjectFactory pFactory) { 105 objectFactory = pFactory; 106 } 107 108 112 public void setMaxTableNameLength(Integer pMaxLength) { 113 maxTableNameLength = pMaxLength; 114 } 115 116 public Integer getMaxTableNameLength() { 117 return maxTableNameLength; 118 } 119 120 124 public void setTableNameCaseSensitive(boolean pTableNameCaseSensitive) { 125 tableNameCaseSensitive = pTableNameCaseSensitive; 126 } 127 128 public boolean isTableNameCaseSensitive() { 129 return tableNameCaseSensitive; 130 } 131 132 136 public void setMaxColumnNameLength(Integer pMaxLength) { 137 maxColumnNameLength = pMaxLength; 138 } 139 140 public Integer getMaxColumnNameLength() { 141 return maxColumnNameLength; 142 } 143 144 148 public void setColumnNameCaseSensitive(boolean pColumnNameCaseSensitive) { 149 columnNameCaseSensitive = pColumnNameCaseSensitive; 150 } 151 152 public boolean isColumnNameCaseSensitive() { 153 return columnNameCaseSensitive; 154 } 155 156 160 public void setSchemaNameCaseSensitive(boolean pSchemaNameCaseSensitive) { 161 schemaNameCaseSensitive = pSchemaNameCaseSensitive; 162 } 163 164 public boolean isSchemaNameCaseSensitive() { 165 return schemaNameCaseSensitive; 166 } 167 168 172 public void setMaxSchemaNameLength(Integer pMaxLength) { 173 maxSchemaNameLength = pMaxLength; 174 } 175 176 public Integer getMaxSchemaNameLength() { 177 return maxSchemaNameLength; 178 } 179 180 182 public SQLFactory.Ident newIdent(String pName) { 183 if (pName == null) { 184 throw new NullPointerException ("An SQL identifier must not be null."); 185 } 186 if (pName.length() == 0) { 187 throw new IllegalArgumentException ("An SQL identifier must not be empty."); 188 } 189 char c = pName.charAt(0); 190 if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) { 191 throw new IllegalArgumentException ("An SQL identifiers first character must be A..Z"); 192 } 193 for (int i = 1; i < pName.length(); i++) { 194 c = pName.charAt(i); 195 if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c > '9')) { 196 throw new IllegalArgumentException ("An SQL identifier must not contain the character " + 197 c + ", only A..Z, a..z, or 0..9 are allowed."); 198 } 199 } 200 return new IdentImpl(pName); 201 } 202 203 public Schema newSchema(String pName) { 204 if (pName == null) { 205 throw new NullPointerException ("A schema name must not be null."); 206 } 207 return newSchema(new SchemaImpl.NameImpl(pName)); 208 } 209 210 public Schema newSchema(Schema.Name pName) { 211 if (pName == null) { 212 throw new NullPointerException ("A schema name must not be null."); 213 } 214 Integer maxLength = getMaxSchemaNameLength(); 215 if (maxLength != null && 216 pName.getName().length() > maxLength.intValue()) { 217 throw new IllegalArgumentException ("The length of the schema name " + pName + 218 " exceeds the valid maximum of " + maxLength); 219 } 220 Schema schema = getSchema(pName); 221 if (schema != null) { 222 throw new IllegalStateException ("A schema named " + schema.getName() + " already exists."); 223 } 224 schema = newSchemaImpl(pName); 225 schemas.add(schema); 226 return schema; 227 } 228 229 public Schema getDefaultSchema() { 230 if (defaultSchema == null) { 231 defaultSchema = newSchemaImpl(null); 232 schemas.add(defaultSchema); 233 } 234 return defaultSchema; 235 } 236 237 public Schema getSchema(String pName) { 238 return getSchema(new SchemaImpl.NameImpl(pName)); 239 } 240 241 public Schema getSchema(Schema.Name pName) { 242 if (pName == null) { 243 throw new NullPointerException ("A schema name must not be null."); 244 } 245 for (Iterator iter = getSchemas(); iter.hasNext();) { 246 Schema schema = (Schema) iter.next(); 247 if (isSchemaNameCaseSensitive()) { 248 if (pName.getName().equalsIgnoreCase(schema.getName().getName())) { 249 return schema; 250 } 251 } else { 252 if (pName.equals(schema.getName())) { 253 return schema; 254 } 255 } 256 } 257 return null; 258 } 259 260 public Iterator getSchemas() { 261 return schemas.iterator(); 262 } 263 264 public SelectStatement newSelectStatement() { 265 return new SelectStatementImpl(this); 266 } 267 268 public InsertStatement newInsertStatement() { 269 return new InsertStatementImpl(this); 270 } 271 272 public UpdateStatement newUpdateStatement() { 273 return new UpdateStatementImpl(this); 274 } 275 276 public DeleteStatement newDeleteStatement() { 277 return new DeleteStatementImpl(this); 278 } 279 280 protected Schema newSchemaImpl(Schema.Name pName) { 281 return new SchemaImpl(this, pName); 282 } 283 284 protected Table newTableImpl(Schema pSchema, Table.Name pName) { 285 return new TableImpl(pSchema, pName); 286 } 287 288 protected Column newColumnImpl(Table pTable, Column.Name pName, Column.Type pType) { 289 return new ColumnImpl(pTable, pName, pType); 290 } 291 292 public SQLGenerator newSQLGenerator() { 293 return new SQLGeneratorImpl(); 294 } 295 296 public Schema getSchema(Connection pConn, String pName) throws SQLException { 297 return getSchema(pConn, pName == null ? null : new SchemaImpl.NameImpl(pName)); 298 } 299 300 private class JDBCTable { 301 private final String catalogName, schemaName, tableName, tableType; 302 private final String toStringValue; 303 private Table table; 304 307 public JDBCTable(String pCatalogName, String pSchemaName, String pTableName, 308 String pTableType) { 309 catalogName = pCatalogName; 310 schemaName = pSchemaName; 311 tableName = pTableName; 312 tableType = pTableType; 313 String s = tableName; 314 if ((schemaName != null && schemaName.length() > 0) || 315 (catalogName != null && catalogName.length() > 0)) { 316 s = catalogName + "." + schemaName + "." + tableName; 317 318 } 319 toStringValue = s; 320 } 321 323 public String getCatalogName() { return catalogName; } 324 326 public String getSchemaName() { return schemaName; } 327 329 public String getTableName() { return tableName; } 330 332 public String getTableType() { return tableType; } 333 public String toString() { return toStringValue; } 334 336 public void setTable(Table pTable) { table = pTable; } 337 339 public Table getTable() { return table; } 340 341 public int hashCode() { 342 int result = 0; 343 if (catalogName != null) result += catalogName.hashCode(); 344 if (schemaName != null) result += schemaName.hashCode(); 345 if (tableName != null) result += tableName.hashCode(); 346 return result; 347 } 348 public boolean equals(Object o) { 349 if (o == null || !(o instanceof JDBCTable)) return false; 350 JDBCTable t = (JDBCTable) o; 351 if (catalogName == null) { 352 if (t.catalogName != null) return false; 353 } else { 354 if (!catalogName.equals(t.catalogName)) return false; 355 } 356 if (schemaName == null) { 357 if (t.schemaName != null) return false; 358 } else { 359 if (!schemaName.equals(t.schemaName)) return false; 360 } 361 if (tableName == null) { 362 return t.tableName == null; 363 } else { 364 return tableName.equals(t.tableName); 365 } 366 } 367 } 368 369 protected Schema makeSchema(Schema.Name pName) { 370 Schema schema; 371 if (pName == null) { 372 schema = getDefaultSchema(); 373 } else { 374 schema = getSchema(pName); 375 if (schema == null) { 376 schema = newSchema(pName); 377 } 378 } 379 return schema; 380 } 381 382 protected JDBCTable[] readTables(DatabaseMetaData pData, Schema.Name pSchema, Table.Name pTable) throws SQLException { 383 final String mName = "readTables"; 384 List tables = new ArrayList (); 385 { 386 ResultSet rs = pData.getTables(null, pSchema == null ? null : pSchema.getName(), 387 pTable == null ? null : pTable.getName(), null); 388 boolean isRsClosed = false; 389 try { 390 while (rs.next()) { 391 JDBCTable table = new JDBCTable(rs.getString(1), rs.getString(2), 392 rs.getString(3), rs.getString(4)); 393 if (!"TABLE".equals(table.getTableType())) { 394 continue; 395 } 396 397 if (pSchema != null) { 398 if (!table.getSchemaName().equals(pSchema.toString())) { 399 continue; 400 } 401 } 402 logger.finest(mName, "Found table " + table); 403 tables.add(table); 404 } 405 isRsClosed = true; 406 rs.close(); 407 } finally { 408 if (!isRsClosed) { try { rs.close(); } catch (Throwable ignore) {} } 409 } 410 } 411 return (JDBCTable[]) tables.toArray(new JDBCTable[tables.size()]); 412 } 413 414 protected Column readColumn(Table pTable, String pColumnName, int pDataType, String pTypeName, 415 long pColumnSize, int pDecimalDigits, int pNullable) { 416 Column.Type type; 417 final String mName = "readColumn"; 418 switch (pDataType) { 419 case Types.BIGINT: type = Column.Type.BIGINT; break; 420 case Types.BINARY: type = Column.Type.BINARY; break; 421 case Types.BIT: type = Column.Type.BIT; break; 422 case Types.BLOB: type = Column.Type.BLOB; break; 423 case 16: 424 type = Column.Type.BIT; break; 425 case Types.CHAR: type = Column.Type.CHAR; break; 426 case Types.CLOB: type = Column.Type.CLOB; break; 427 case Types.DATE: type = Column.Type.DATE; break; 428 case Types.DOUBLE: type = Column.Type.DOUBLE; break; 429 case Types.FLOAT: type = Column.Type.FLOAT; break; 430 case Types.REAL: type = Column.Type.DOUBLE; break; 431 case Types.INTEGER: type = Column.Type.INTEGER; break; 432 case Types.LONGVARBINARY: type = Column.Type.VARBINARY; break; 433 case Types.LONGVARCHAR: type = Column.Type.VARCHAR; break; 434 case Types.OTHER: type = Column.Type.OTHER; break; 435 case Types.SMALLINT: type = Column.Type.SMALLINT; break; 436 case Types.TIMESTAMP: type = Column.Type.TIMESTAMP; break; 437 case Types.TIME: type = Column.Type.TIME; break; 438 case Types.TINYINT: type = Column.Type.TINYINT; break; 439 case Types.VARBINARY: type = Column.Type.VARBINARY; break; 440 case Types.VARCHAR: type = Column.Type.VARCHAR; break; 441 default: throw new IllegalArgumentException ("Column " + pColumnName + 442 " in table " + pTable.getQName() + 443 " has unknown JDBC data type " + 444 pDataType); 445 } 446 Column column = pTable.newColumn(pColumnName, type); 447 logger.finest(mName, "Found column " + pColumnName); 448 if (column instanceof StringColumn) { 449 ((StringColumn) column).setLength(pColumnSize); 450 } else if (column instanceof BinaryColumn) { 451 ((BinaryColumn) column).setLength(pColumnSize); 452 } 453 if (pNullable == DatabaseMetaData.columnNullable) { 454 column.setNullable(true); 455 } 456 return column; 457 } 458 459 protected Table readTable(DatabaseMetaData pData, Schema pSchema, JDBCTable pTable) 460 throws SQLException { 461 final String mName = "readTable"; 462 ResultSet rs = pData.getColumns(pTable.getCatalogName(), pTable.getSchemaName(), 463 pTable.getTableName(), null); 464 boolean isRsClosed = false; 465 try { 466 Table sqlTable = pSchema.newTable(pTable.getTableName()); 467 logger.finest(mName, "Looking for columns of " + pTable + "=" + sqlTable.getQName()); 468 while (rs.next()) { 469 String columnName = rs.getString(4); 470 int dataType = rs.getInt(5); 471 String typeName = rs.getString(6); 472 long columnSize = rs.getLong(7); 473 int decimalDigits = rs.getInt(9); 474 int isNullable = rs.getInt(11); 475 readColumn(sqlTable, columnName, dataType, typeName, columnSize, decimalDigits, isNullable); 476 } 477 pTable.setTable(sqlTable); 478 479 isRsClosed = true; 480 rs.close(); 481 return sqlTable; 482 } finally { 483 if (!isRsClosed) { try { rs.close(); } catch (Throwable ignore) {} } 484 } 485 } 486 487 protected Index readPrimaryKey(DatabaseMetaData pData, JDBCTable pTable) throws SQLException { 488 final String mName = "readPrimaryKey"; 489 logger.finest(mName, "Looking for primary keys of " + pTable + "=" + pTable.getTable().getQName()); 490 ResultSet rs = pData.getPrimaryKeys(pTable.getCatalogName(), 491 pTable.getSchemaName(), 492 pTable.getTableName()); 493 Index primaryKey = null; 494 boolean isRsClosed = false; 495 try { 496 while (rs.next()) { 497 if (primaryKey == null) { 498 primaryKey = pTable.getTable().newPrimaryKey(); 499 } 500 501 String columnName = rs.getString(4); 502 logger.finest(mName, "Found column " + columnName); 503 primaryKey.addColumn(columnName); 504 } 505 506 isRsClosed = true; 507 rs.close(); 508 } finally { 509 if (!isRsClosed) { try { rs.close(); } catch (Throwable ignore) {} } 510 } 511 return primaryKey; 512 } 513 514 protected ForeignKey[] readForeignKeys(DatabaseMetaData pData, JDBCTable pTable, JDBCTable[] pTables) 515 throws SQLException { 516 final String mName = "readForeignKeys"; 517 logger.finest(mName, "Looking for foreign keys of " + pTable + "=" + pTable.getTable().getQName()); 518 List result = new ArrayList (); 519 ResultSet rs = pData.getImportedKeys(pTable.getCatalogName(), 520 pTable.getSchemaName(), 521 pTable.getTableName()); 522 ForeignKey foreignKey = null; 523 boolean isRsClosed = false; 524 try { 525 while (rs.next()) { 526 JDBCTable referencedTable = new JDBCTable(rs.getString(1), rs.getString(2), 527 rs.getString(3), "TABLE"); 528 String referencedColumnName = rs.getString(4); 529 String localColumnName = rs.getString(8); 530 logger.finest(mName, "Found column " + localColumnName + " referencing " + 531 referencedColumnName + " in " + referencedTable); 532 for (int i = 0; i < pTables.length; i++) { 533 JDBCTable refIterTable = pTables[i]; 534 if (refIterTable.equals(referencedTable)) { 535 referencedTable.setTable(refIterTable.getTable()); 536 break; 537 } 538 } 539 if (referencedTable.getTable() == null) { 540 logger.finest(mName, "Unknown table, ignoring"); 541 continue; 542 } 543 544 short seq = rs.getShort(9); 545 if (seq == 1) { 546 foreignKey = pTable.getTable().newForeignKey(referencedTable.getTable()); 547 result.add(foreignKey); 548 } 549 foreignKey.addColumnLink(localColumnName, referencedColumnName); 550 } 551 552 isRsClosed = true; 553 rs.close(); 554 } finally { 555 if (!isRsClosed) { try { rs.close(); } catch (Throwable ignore) {} } 556 } 557 return (ForeignKey[]) result.toArray(new ForeignKey[result.size()]); 558 } 559 560 public Schema getSchema(Connection pConn, Schema.Name pName) throws SQLException { 561 final String mName = "getSchema(Connection,Schema.Name)"; 562 logger.finest(mName, "->", new Object []{pConn, pName}); 563 564 Schema schema = makeSchema(pName); 565 DatabaseMetaData metaData = pConn.getMetaData(); 566 JDBCTable[] tables = readTables(metaData, pName, null); 567 for (int i = 0; i < tables.length; i++) { 568 readTable(metaData, schema, tables[i]); 569 readPrimaryKey(metaData, tables[i]); 570 } 571 572 for (int i = 0; i < tables.length; i++) { 573 readForeignKeys(metaData, tables[i], tables); 574 } 575 576 logger.finest(mName, "<-", schema); 577 return schema; 578 } 579 580 public Table getTable(Connection pConnection, Schema.Name pSchema, Table.Name pTable) throws SQLException { 581 final String mName = "getSchema(Connection,Schema.Name)"; 582 logger.finest(mName, "->", new Object []{pConnection, pSchema, pTable}); 583 584 Schema schema = makeSchema(pSchema); 585 DatabaseMetaData metaData = pConnection.getMetaData(); 586 JDBCTable[] tables = readTables(metaData, pSchema, pTable); 587 JDBCTable jdbcTable; 588 if (tables.length == 0) { 589 String tableName = pTable.toString(); 590 String schemaName = pSchema == null ? null : pSchema.toString(); 591 String ucTableName = tableName.toUpperCase(); 592 String ucSchemaName = schemaName == null ? null : schemaName.toUpperCase(); 593 if (tableName.equals(ucTableName) && 594 (schemaName == null || schemaName.equals(ucSchemaName))) { 595 throw new IllegalStateException ("No table named " + pTable + " found in schema " + pSchema); 596 } 597 return getTable(pConnection, ucSchemaName, ucTableName); 598 } else if (tables.length == 1) { 599 jdbcTable = tables[0]; 600 } else { 601 throw new IllegalStateException ("Multiple tables named " + pTable + " found in schema " + pSchema); 602 } 603 Table result = readTable(metaData, schema, jdbcTable); 604 readPrimaryKey(metaData, jdbcTable); 605 return result; 606 } 607 608 public Table getTable(Connection pConnection, String pSchema, String pTable) throws SQLException { 609 return getTable(pConnection, pSchema == null ? null : new SchemaImpl.NameImpl(pSchema), new TableImpl.NameImpl(pTable)); 610 } 611 } 612 | Popular Tags |