1 19 20 21 package org.apache.cayenne.dba; 22 23 import java.net.URL ; 24 import java.sql.PreparedStatement ; 25 import java.sql.SQLException ; 26 import java.util.Calendar ; 27 import java.util.Collection ; 28 import java.util.GregorianCalendar ; 29 import java.util.Iterator ; 30 31 import org.apache.cayenne.CayenneRuntimeException; 32 import org.apache.cayenne.access.DataNode; 33 import org.apache.cayenne.access.trans.QualifierTranslator; 34 import org.apache.cayenne.access.trans.QueryAssembler; 35 import org.apache.cayenne.access.types.BigIntegerType; 36 import org.apache.cayenne.access.types.BooleanType; 37 import org.apache.cayenne.access.types.ByteArrayType; 38 import org.apache.cayenne.access.types.CalendarType; 39 import org.apache.cayenne.access.types.CharType; 40 import org.apache.cayenne.access.types.ExtendedType; 41 import org.apache.cayenne.access.types.ExtendedTypeMap; 42 import org.apache.cayenne.access.types.UtilDateType; 43 import org.apache.cayenne.map.DbAttribute; 44 import org.apache.cayenne.map.DbEntity; 45 import org.apache.cayenne.map.DbJoin; 46 import org.apache.cayenne.map.DbRelationship; 47 import org.apache.cayenne.map.DerivedDbEntity; 48 import org.apache.cayenne.query.Query; 49 import org.apache.cayenne.query.SQLAction; 50 import org.apache.cayenne.util.ResourceLocator; 51 import org.apache.cayenne.util.Util; 52 53 59 public class JdbcAdapter implements DbAdapter { 60 61 protected PkGenerator pkGenerator; 62 protected TypesHandler typesHandler; 63 protected ExtendedTypeMap extendedTypes; 64 protected boolean supportsBatchUpdates; 65 protected boolean supportsFkConstraints; 66 protected boolean supportsUniqueConstraints; 67 protected boolean supportsGeneratedKeys; 68 69 72 public JdbcAdapter() { 73 this.setSupportsBatchUpdates(false); 75 this.setSupportsUniqueConstraints(true); 76 this.setSupportsFkConstraints(true); 77 78 this.pkGenerator = this.createPkGenerator(); 79 this.typesHandler = TypesHandler.getHandler(findAdapterResource("/types.xml")); 80 this.extendedTypes = new ExtendedTypeMap(); 81 this.configureExtendedTypes(extendedTypes); 82 } 83 84 89 public String getBatchTerminator() { 90 return ";"; 91 } 92 93 104 public URL findAdapterResource(String name) { 105 Class adapterClass = this.getClass(); 106 107 while (adapterClass != null && JdbcAdapter.class.isAssignableFrom(adapterClass)) { 108 109 String path = Util.getPackagePath(adapterClass.getName()) + name; 110 URL url = ResourceLocator.findURLInClasspath(path); 111 if (url != null) { 112 return url; 113 } 114 115 adapterClass = adapterClass.getSuperclass(); 116 } 117 118 return null; 119 } 120 121 125 protected void configureExtendedTypes(ExtendedTypeMap map) { 126 map.registerType(new BooleanType()); 129 130 map.registerType(new CharType(false, true)); 134 135 map.registerType(new UtilDateType()); 137 138 map.registerType(new ByteArrayType(false, true)); 140 141 map.registerType(new CalendarType(GregorianCalendar .class)); 145 map.registerType(new CalendarType(Calendar .class)); 146 147 map.registerType(new BigIntegerType()); 148 } 149 150 155 protected PkGenerator createPkGenerator() { 156 return new JdbcPkGenerator(); 157 } 158 159 162 public PkGenerator getPkGenerator() { 163 return pkGenerator; 164 } 165 166 171 public void setPkGenerator(PkGenerator pkGenerator) { 172 this.pkGenerator = pkGenerator; 173 } 174 175 178 public boolean supportsFkConstraints() { 179 return supportsFkConstraints; 180 } 181 182 185 public void setSupportsFkConstraints(boolean flag) { 186 this.supportsFkConstraints = flag; 187 } 188 189 194 public boolean supportsUniqueConstraints() { 195 return supportsUniqueConstraints; 196 } 197 198 201 public void setSupportsUniqueConstraints(boolean flag) { 202 this.supportsUniqueConstraints = flag; 203 } 204 205 208 public String dropTable(DbEntity ent) { 209 return "DROP TABLE " + ent.getFullyQualifiedName(); 210 } 211 212 216 public String createTable(DbEntity entity) { 217 if (entity instanceof DerivedDbEntity) { 218 throw new CayenneRuntimeException("Can't create table for derived DbEntity '" 219 + entity.getName() 220 + "'."); 221 } 222 223 StringBuffer sqlBuffer = new StringBuffer (); 224 sqlBuffer.append("CREATE TABLE ").append(entity.getFullyQualifiedName()).append( 225 " ("); 226 227 Iterator it = entity.getAttributes().iterator(); 229 if (it.hasNext()) { 230 boolean first = true; 231 while (it.hasNext()) { 232 if (first) { 233 first = false; 234 } 235 else { 236 sqlBuffer.append(", "); 237 } 238 239 DbAttribute column = (DbAttribute) it.next(); 240 241 if (column.getType() == TypesMapping.NOT_DEFINED) { 243 throw new CayenneRuntimeException("Undefined type for attribute '" 244 + entity.getFullyQualifiedName() 245 + "." 246 + column.getName() 247 + "'."); 248 } 249 250 createTableAppendColumn(sqlBuffer, column); 251 } 252 253 254 createTableAppendPKClause(sqlBuffer, entity); 255 } 256 257 sqlBuffer.append(')'); 258 return sqlBuffer.toString(); 259 } 260 261 264 protected void createTableAppendPKClause(StringBuffer sqlBuffer, DbEntity entity) { 265 Iterator pkit = entity.getPrimaryKey().iterator(); 266 if (pkit.hasNext()) { 267 sqlBuffer.append(", PRIMARY KEY ("); 268 boolean firstPk = true; 269 while (pkit.hasNext()) { 270 if (firstPk) 271 firstPk = false; 272 else 273 sqlBuffer.append(", "); 274 275 DbAttribute at = (DbAttribute) pkit.next(); 276 sqlBuffer.append(at.getName()); 277 } 278 sqlBuffer.append(')'); 279 } 280 } 281 282 287 protected void createTableAppendColumn(StringBuffer sqlBuffer, DbAttribute column) { 288 String [] types = externalTypesForJdbcType(column.getType()); 289 if (types == null || types.length == 0) { 290 String entityName = column.getEntity() != null ? ((DbEntity) column 291 .getEntity()).getFullyQualifiedName() : "<null>"; 292 throw new CayenneRuntimeException("Undefined type for attribute '" 293 + entityName 294 + "." 295 + column.getName() 296 + "': " 297 + column.getType()); 298 } 299 300 String type = types[0]; 301 sqlBuffer.append(column.getName()).append(' ').append(type); 302 303 if (TypesMapping.supportsLength(column.getType())) { 305 int len = column.getMaxLength(); 306 int scale = TypesMapping.isDecimal(column.getType()) 307 ? column.getScale() 308 : -1; 309 310 if (scale > len) { 312 scale = -1; 313 } 314 315 if (len > 0) { 316 sqlBuffer.append('(').append(len); 317 318 if (scale >= 0) { 319 sqlBuffer.append(", ").append(scale); 320 } 321 322 sqlBuffer.append(')'); 323 } 324 } 325 326 sqlBuffer.append(column.isMandatory() ? " NOT NULL" : " NULL"); 327 } 328 329 334 public String createUniqueConstraint(DbEntity source, Collection columns) { 335 if (columns == null || columns.isEmpty()) { 336 throw new CayenneRuntimeException( 337 "Can't create UNIQUE constraint - no columns specified."); 338 } 339 340 StringBuffer buf = new StringBuffer (); 341 342 buf.append("ALTER TABLE ").append(source.getFullyQualifiedName()).append( 343 " ADD UNIQUE ("); 344 345 Iterator it = columns.iterator(); 346 DbAttribute first = (DbAttribute) it.next(); 347 buf.append(first.getName()); 348 349 while (it.hasNext()) { 350 DbAttribute next = (DbAttribute) it.next(); 351 buf.append(", "); 352 buf.append(next.getName()); 353 } 354 355 buf.append(")"); 356 357 return buf.toString(); 358 } 359 360 364 public String createFkConstraint(DbRelationship rel) { 365 StringBuffer buf = new StringBuffer (); 366 StringBuffer refBuf = new StringBuffer (); 367 368 buf.append("ALTER TABLE ").append( 369 ((DbEntity) rel.getSourceEntity()).getFullyQualifiedName()).append( 370 " ADD FOREIGN KEY ("); 371 372 Iterator jit = rel.getJoins().iterator(); 373 boolean first = true; 374 while (jit.hasNext()) { 375 DbJoin join = (DbJoin) jit.next(); 376 if (!first) { 377 buf.append(", "); 378 refBuf.append(", "); 379 } 380 else 381 first = false; 382 383 buf.append(join.getSourceName()); 384 refBuf.append(join.getTargetName()); 385 } 386 387 buf 388 .append(") REFERENCES ") 389 .append(((DbEntity) rel.getTargetEntity()).getFullyQualifiedName()) 390 .append(" (") 391 .append(refBuf.toString()) 392 .append(')'); 393 return buf.toString(); 394 } 395 396 public String [] externalTypesForJdbcType(int type) { 397 return typesHandler.externalTypesForJdbcType(type); 398 } 399 400 public ExtendedTypeMap getExtendedTypes() { 401 return extendedTypes; 402 } 403 404 public DbAttribute buildAttribute( 405 String name, 406 String typeName, 407 int type, 408 int size, 409 int scale, 410 boolean allowNulls) { 411 412 DbAttribute attr = new DbAttribute(); 413 attr.setName(name); 414 attr.setType(type); 415 attr.setMandatory(!allowNulls); 416 417 if (size >= 0) { 418 attr.setMaxLength(size); 419 } 420 421 if (scale >= 0) { 422 attr.setScale(scale); 423 } 424 425 return attr; 426 } 427 428 public String tableTypeForTable() { 429 return "TABLE"; 430 } 431 432 public String tableTypeForView() { 433 return "VIEW"; 434 } 435 436 439 public QualifierTranslator getQualifierTranslator(QueryAssembler queryAssembler) { 440 return new QualifierTranslator(queryAssembler); 441 } 442 443 448 public SQLAction getAction(Query query, DataNode node) { 449 return query 450 .createSQLAction(new JdbcActionBuilder(this, node.getEntityResolver())); 451 } 452 453 public void bindParameter( 454 PreparedStatement statement, 455 Object object, 456 int pos, 457 int sqlType, 458 int scale) throws SQLException , Exception { 459 460 if (object == null) { 461 statement.setNull(pos, sqlType); 462 } 463 else { 464 ExtendedType typeProcessor = getExtendedTypes().getRegisteredType( 465 object.getClass()); 466 typeProcessor.setJdbcObject(statement, object, pos, sqlType, scale); 467 } 468 } 469 470 public boolean supportsBatchUpdates() { 471 return this.supportsBatchUpdates; 472 } 473 474 public void setSupportsBatchUpdates(boolean flag) { 475 this.supportsBatchUpdates = flag; 476 } 477 478 481 public boolean supportsGeneratedKeys() { 482 return supportsGeneratedKeys; 483 } 484 485 488 public void setSupportsGeneratedKeys(boolean flag) { 489 this.supportsGeneratedKeys = flag; 490 } 491 } 492 | Popular Tags |