1 29 30 package com.caucho.amber.manager; 31 32 import com.caucho.amber.AmberException; 33 import com.caucho.amber.cfg.ColumnResultConfig; 34 import com.caucho.amber.cfg.EntityResultConfig; 35 import com.caucho.amber.cfg.FieldResultConfig; 36 import com.caucho.amber.cfg.SqlResultSetMappingConfig; 37 import com.caucho.amber.entity.Entity; 38 import com.caucho.amber.entity.EntityItem; 39 import com.caucho.amber.query.AbstractQuery; 40 import com.caucho.amber.query.SelectQuery; 41 import com.caucho.amber.query.UserQuery; 42 import com.caucho.amber.type.CalendarType; 43 import com.caucho.amber.type.EntityType; 44 import com.caucho.amber.type.UtilDateType; 45 import com.caucho.ejb.EJBExceptionWrapper; 46 import com.caucho.util.L10N; 47 48 import javax.persistence.FlushModeType; 49 import javax.persistence.NonUniqueResultException; 50 import javax.persistence.NoResultException; 51 import javax.persistence.Query; 52 import javax.persistence.TemporalType; 53 import java.lang.reflect.Constructor ; 54 import java.sql.PreparedStatement ; 55 import java.sql.ResultSet ; 56 import java.sql.ResultSetMetaData ; 57 import java.sql.SQLException ; 58 import java.sql.Types ; 59 import java.util.ArrayList ; 60 import java.util.Calendar ; 61 import java.util.Date ; 62 import java.util.List ; 63 64 67 public class QueryImpl implements Query { 68 private static final L10N L = new L10N(QueryImpl.class); 69 70 private AbstractQuery _query; 71 private UserQuery _userQuery; 72 73 private AmberConnection _aConn; 74 private int _firstResult; 75 76 private int _currIndex; 77 78 private FlushModeType _flushMode; 79 80 private Class _primitiveColumns[]; 82 83 private String _nativeSql; 85 private SqlResultSetMappingConfig _sqlResultSetMapping; 86 private int _currEntityResult; 87 private int _currColumnResult; 88 89 92 QueryImpl(AbstractQuery query, AmberConnection aConn) 93 { 94 _query = query; 95 _aConn = aConn; 96 97 _userQuery = new UserQuery(query); 98 _userQuery.setSession(_aConn); 99 } 100 101 104 QueryImpl(AmberConnection aConn) 105 { 106 _aConn = aConn; 107 } 108 109 112 public List getResultList() 113 { 114 try { 115 116 Class constructorClass = null; 117 118 if (isSelectQuery()) { 119 if (! isNativeQuery()) { 120 SelectQuery selectQuery = (SelectQuery) _query; 121 constructorClass = selectQuery.getConstructorClass(); 122 } 123 } 124 else 125 throw new IllegalStateException (L.l("javax.persistence.Query.getResultList() can only be applied to a SELECT statement")); 126 127 Constructor constructor = null; 128 129 ArrayList results = new ArrayList (); 130 131 ResultSet rs = executeQuery(); 132 133 ResultSetMetaData metaData = null; 134 int columnCount = -1; 135 136 int n = 0; 137 138 Object row[] = null; 139 140 ArrayList columns = new ArrayList (); 141 142 while (rs.next()) { 143 Object object = null; 144 145 _currIndex = 1; 146 147 if (n == 0) { 148 149 try { 150 151 metaData = rs.getMetaData(); 152 153 if (metaData != null) 154 columnCount = metaData.getColumnCount(); 155 156 } catch (Exception ex) { 157 metaData = null; 160 } 161 162 if (columnCount <= 0) 163 columnCount = 10000; 164 165 for (int i=1; i <= columnCount; i++) { 166 167 int columnType = -1; 168 169 try { 170 columnType = metaData.getColumnType(i); 171 } catch (Exception ex) { 172 } 173 174 try { 175 176 if (isNativeQuery()) { 177 ArrayList <EntityResultConfig> entityResults 178 = _sqlResultSetMapping.getEntityResults(); 179 180 if (_currEntityResult == entityResults.size()) { 181 182 ArrayList <ColumnResultConfig> columnResults 183 = _sqlResultSetMapping.getColumnResults(); 184 185 if (_currColumnResult == columnResults.size()) 186 break; 187 } 188 189 object = getInternalNative(rs); 190 } 191 else { 192 object = getInternalObject(rs, columnType); 193 } 194 195 columns.add(object); 196 197 } catch (IndexOutOfBoundsException ex1) { 198 break; 199 } 200 } 204 205 n = columns.size(); 206 row = columns.toArray(); 207 208 if (constructorClass != null) { 209 210 _primitiveColumns = new Class [row.length]; 211 212 StringBuilder argValues = new StringBuilder (); 213 214 try { 215 217 boolean isFirst = true; 218 219 for (int i=0; i < n; i++) { 220 if (isFirst) 221 isFirst = false; 222 else 223 argValues.append(", "); 224 225 argValues.append(row[i]); 226 } 227 228 Constructor ctors[] = constructorClass.getDeclaredConstructors(); 229 230 ArrayList <Constructor > validConstructors 231 = new ArrayList <Constructor >(); 232 233 for (int j=0; j < ctors.length; j++) { 234 235 Class paramTypes[] = ctors[j].getParameterTypes(); 236 237 if (paramTypes.length != row.length) 238 continue; 239 240 boolean isValid = true; 241 242 for (int k=0; k < paramTypes.length; k++) { 243 Class columnClass = row[k].getClass(); 244 245 if (! paramTypes[k].isAssignableFrom(columnClass)) { 246 247 if (! paramTypes[k].isPrimitive()) { 248 isValid = false; 249 break; 250 } 251 252 Class primitiveType 253 = (Class ) columnClass.getDeclaredField("TYPE").get(null); 254 255 if (paramTypes[k].isAssignableFrom(primitiveType)) { 256 _primitiveColumns[k] = primitiveType; 258 } 259 else { 260 isValid = false; 261 break; 262 } 263 } 264 } 265 266 if (isValid) 267 validConstructors.add(ctors[j]); 268 } 269 270 constructor = validConstructors.get(0); 271 272 } catch (Exception ex) { 273 throw error(L.l("Unable to find constructor {0}. Make sure there is a public constructor for the given argument values ({1})", constructorClass.getName(), argValues)); 274 } 275 } 276 } 277 else { 278 279 row = new Object [n]; 280 281 for (int i=0; i < n; i++) { 282 283 int columnType = -1; 284 285 try { 286 columnType = metaData.getColumnType(i + 1); 287 } catch (Exception ex) { 288 } 289 290 if (isNativeQuery()) 291 row[i] = getInternalNative(rs); 292 else 293 row[i] = getInternalObject(rs, columnType); 294 } 295 } 296 297 if (constructor == null) { 298 if (n == 1) 299 results.add(row[0]); 300 else 301 results.add(row); 302 } 303 else { 304 305 try { 306 for (int i=0; i < row.length; i++) { 307 Class primitiveType = _primitiveColumns[i]; 308 309 if (primitiveType == null) 310 continue; 311 312 if (primitiveType == Boolean.TYPE) 314 row[i] = ((Boolean ) row[i]).booleanValue(); 315 else if (primitiveType == Byte.TYPE) 316 row[i] = ((Byte ) row[i]).byteValue(); 317 else if (primitiveType == Character.TYPE) 318 row[i] = ((Character ) row[i]).charValue(); 319 else if (primitiveType == Double.TYPE) 320 row[i] = ((Double ) row[i]).doubleValue(); 321 else if (primitiveType == Float.TYPE) 322 row[i] = ((Float ) row[i]).floatValue(); 323 else if (primitiveType == Integer.TYPE) 324 row[i] = ((Integer ) row[i]).intValue(); 325 else if (primitiveType == Long.TYPE) 326 row[i] = ((Long ) row[i]).longValue(); 327 else if (primitiveType == Short.TYPE) 328 row[i] = ((Short ) row[i]).shortValue(); 329 } 330 331 object = constructor.newInstance(row); 332 } catch (Exception ex) { 333 334 StringBuilder argTypes = new StringBuilder (); 335 336 boolean isFirst = true; 337 338 for (int i=0; i < row.length; i++) { 339 340 if (isFirst) 341 isFirst = false; 342 else 343 argTypes.append(", "); 344 345 if (row[i] == null) 346 argTypes.append("null"); 347 else 348 argTypes.append(row[i].toString()); } 350 351 throw error(L.l("Unable to instantiate {0} with parameters ({1}).", constructorClass.getName(), argTypes)); 352 } 353 354 results.add(object); 355 } 356 } 357 358 rs.close(); 359 360 return results; 361 } catch (Exception e) { 362 throw EJBExceptionWrapper.createRuntime(e); 363 } 364 } 365 366 369 public Object getSingleResult() 370 { 371 try { 372 if (! isSelectQuery()) 373 throw new IllegalStateException (L.l("javax.persistence.Query.getSingleResult() can only be applied to a SELECT statement")); 374 375 ResultSet rs = executeQuery(); 376 377 Object value = null; 378 379 if (rs.next()) 380 value = rs.getObject(1); 381 else throw new NoResultException("Query returned no results for getSingleResult()"); 383 384 if (rs.next()) 386 throw new NonUniqueResultException("Query returned more than one result for getSingleResult()"); 387 388 rs.close(); 389 390 return value; 391 } catch (Exception e) { 392 throw EJBExceptionWrapper.createRuntime(e); 393 } 394 } 395 396 399 public int executeUpdate() 400 { 401 try { 402 if (isSelectQuery()) 404 throw new IllegalStateException (L.l("javax.persistence.Query.executeUpdate() cannot be applied to a SELECT statement")); 405 406 if (_flushMode == FlushModeType.AUTO) 407 _aConn.flushNoChecks(); 408 409 return _userQuery.executeUpdate(); 410 } catch (Exception e) { 411 throw EJBExceptionWrapper.createRuntime(e); 412 } 413 } 414 415 418 protected ResultSet executeQuery() 419 throws SQLException 420 { 421 ResultSet rs; 422 423 if (_flushMode == FlushModeType.AUTO) 424 _aConn.flushNoChecks(); 425 426 if (_nativeSql == null) { 427 rs = _userQuery.executeQuery(); 429 } 430 else { 431 433 PreparedStatement pstmt = _aConn.prepareStatement(_nativeSql); 434 435 rs = pstmt.executeQuery(); 436 } 437 438 return rs; 439 } 440 441 444 public Query setMaxResults(int maxResults) 445 { 446 if (maxResults < 0) 447 throw new IllegalArgumentException (L.l("setMaxResults() needs a non-negative argument, '{0}' is not allowed", maxResults)); 448 449 _userQuery.setMaxResults(maxResults); 450 451 return this; 452 } 453 454 457 public Query setFirstResult(int startPosition) 458 { 459 if (startPosition < 0) 460 throw new IllegalArgumentException ("setFirstResult() requires a non-negative argument"); 461 462 _userQuery.setFirstResult(startPosition); 463 464 return this; 465 } 466 467 470 public Query setHint(String hintName, Object value) 471 { 472 return this; 473 } 474 475 478 public Query setParameter(String name, Object value) 479 { 480 ArrayList <String > mapping = _query.getPreparedMapping(); 481 482 int n = mapping.size(); 483 484 boolean found = false; 485 486 for (int i=0; i < n; i++) { 487 if (mapping.get(i).equals(name)) { 488 setParameter(i+1, value); 489 found = true; 490 } 491 } 492 493 if (! found) 494 throw new IllegalArgumentException (L.l("Parameter name '{0}' is invalid", name)); 495 496 return this; 497 } 498 499 502 public Query setParameter(String name, Date value, TemporalType type) 503 { 504 ArrayList <String > mapping = _query.getPreparedMapping(); 505 506 int n = mapping.size(); 507 508 boolean found = false; 509 510 for (int i=0; i < n; i++) { 511 if (mapping.get(i).equals(name)) { 512 setParameter(i+1, value, type); 513 found = true; 514 } 515 } 516 517 if (! found) 518 throw new IllegalArgumentException (L.l("Parameter name '{0}' is invalid", name)); 519 520 return this; 521 } 522 523 526 public Query setParameter(String name, Calendar value, TemporalType type) 527 { 528 ArrayList <String > mapping = _query.getPreparedMapping(); 529 530 int n = mapping.size(); 531 532 boolean found = false; 533 534 for (int i=0; i < n; i++) { 535 if (mapping.get(i).equals(name)) { 536 setParameter(i+1, value, type); 537 found = true; 538 } 539 } 540 541 if (! found) 542 throw new IllegalArgumentException (L.l("Parameter name '{0}' is invalid", name)); 543 544 return this; 545 } 546 547 550 public Query setParameter(int index, Object value) 551 { 552 try { 553 if (value == null) { 554 _userQuery.setNull(index, java.sql.Types.JAVA_OBJECT); 555 return this; 556 } 557 558 if (value instanceof Byte ) 559 _userQuery.setByte(index, ((Byte ) value).byteValue()); 560 if (value instanceof Short ) 561 _userQuery.setShort(index, ((Short ) value).shortValue()); 562 if (value instanceof Integer ) 563 _userQuery.setInt(index, ((Integer ) value).intValue()); 564 if (value instanceof Long ) 565 _userQuery.setLong(index, ((Long ) value).longValue()); 566 if (value instanceof Float ) 567 _userQuery.setFloat(index, ((Float ) value).floatValue()); 568 if (value instanceof Double ) _userQuery.setDouble(index, ((Double ) value).doubleValue()); 570 else if (value instanceof Character ) 571 _userQuery.setString(index, value.toString()); 572 else if (value instanceof Entity) { 573 575 Object pk = ((Entity) value).__caucho_getPrimaryKey(); 576 577 _userQuery.setObject(index, pk); 578 } 579 else { 580 _userQuery.setObject(index, value); 581 } 582 583 return this; 584 } catch (IndexOutOfBoundsException e) { 585 throw new IllegalArgumentException (L.l("Parameter index '{0}' is not valid for setParameter()", index)); 586 } 587 } 588 589 592 public Query setParameter(int index, Date value, TemporalType type) 593 { 594 try { 595 if (value == null) 596 _userQuery.setNull(index, Types.JAVA_OBJECT); 597 else { 598 switch (type) { 599 case TIME: 600 _userQuery.setObject(index, value, UtilDateType.TEMPORAL_TIME_TYPE); 601 break; 602 603 case DATE: 604 _userQuery.setObject(index, value, UtilDateType.TEMPORAL_DATE_TYPE); 605 break; 606 607 default: 608 _userQuery.setObject(index, value, UtilDateType.TEMPORAL_TIMESTAMP_TYPE); 609 } 610 } 611 612 return this; 613 } catch (IndexOutOfBoundsException e) { 614 throw new IllegalArgumentException (L.l("Parameter index '{0}' is not valid for setParameter()", index)); 615 } 616 } 617 618 621 public Query setParameter(int index, Calendar value, TemporalType type) 622 { 623 try { 624 if (value == null) 625 _userQuery.setNull(index, Types.JAVA_OBJECT); 626 else { 627 switch (type) { 628 case TIME: 629 _userQuery.setObject(index, value, CalendarType.TEMPORAL_TIME_TYPE); 630 break; 631 632 case DATE: 633 _userQuery.setObject(index, value, CalendarType.TEMPORAL_DATE_TYPE); 634 break; 635 636 default: 637 _userQuery.setObject(index, value, CalendarType.TEMPORAL_TIMESTAMP_TYPE); 638 } 639 } 640 641 return this; 642 } catch (IndexOutOfBoundsException e) { 643 throw new IllegalArgumentException (L.l("Parameter index '{0}' is not valid for setParameter()", index)); 644 } 645 } 646 647 650 public Query setFlushMode(FlushModeType mode) 651 { 652 _flushMode = mode; 653 654 return this; 655 } 656 657 660 663 public Query setDouble(int index, double value) 664 { 665 _userQuery.setDouble(index, value); 666 667 return this; 668 } 669 670 673 protected void setNativeSql(String sql) 674 { 675 _nativeSql = sql; 676 } 677 678 681 protected void setSqlResultSetMapping(SqlResultSetMappingConfig map) 682 { 683 _sqlResultSetMapping = map; 684 } 685 686 689 private boolean isSelectQuery() 690 { 691 if (_query instanceof SelectQuery) 692 return true; 693 694 if (isNativeQuery()) { 695 String sql = _nativeSql.trim().toUpperCase(); 696 697 if (sql.startsWith("SELECT")) 698 return true; 699 } 700 701 return false; 702 } 703 704 707 private boolean isNativeQuery() 708 { 709 return _nativeSql != null; 710 } 711 712 715 private AmberException error(String msg) 716 { 717 msg += "\nin \"" + _query.getQueryString() + "\""; 718 719 return new AmberException(msg); 720 } 721 722 726 private Object getInternalNative(ResultSet rs) 727 throws Exception 728 { 729 int oldEntityResult = _currEntityResult; 730 731 ArrayList <EntityResultConfig> entityResults 732 = _sqlResultSetMapping.getEntityResults(); 733 734 if (oldEntityResult == entityResults.size()) { 735 736 ArrayList <ColumnResultConfig> columnResults 737 = _sqlResultSetMapping.getColumnResults(); 738 739 if (_currColumnResult == columnResults.size()) { 740 _currColumnResult = 0; 741 } 742 else { 743 _currColumnResult++; 744 745 if (columnResults.size() > 0) { 746 Object object = rs.getObject(_currIndex++); 747 748 return object; 749 } 750 } 751 752 oldEntityResult = 0; 753 _currEntityResult = 0; 754 } 755 756 _currEntityResult++; 757 758 EntityResultConfig entityResult = entityResults.get(oldEntityResult); 759 760 String className = entityResult.getEntityClass(); 761 762 EntityType entityType = _aConn.getPersistenceUnit().getEntity(className); 763 764 if (entityType == null) 765 throw new IllegalStateException (L.l("Unable to locate entity '{0}' for native query.", className)); 766 767 int oldIndex = _currIndex; 768 769 _currIndex++; 770 771 779 780 int keyLength = entityType.getId().getKeyCount(); 781 782 ArrayList <FieldResultConfig> fieldResults 783 = entityResult.getFieldResults(); 784 785 Entity entity = null; 786 787 entity = (Entity) _aConn.load(className, rs.getObject(oldIndex)); 789 790 int consumed = entity.__caucho_load(_aConn, rs, oldIndex + keyLength); 791 792 794 _currIndex += consumed; 795 796 return entity; 797 } 798 799 803 private Object getInternalObject(ResultSet rs, 804 int columnType) 805 throws Exception 806 { 807 809 int oldIndex = _currIndex; 810 811 _currIndex++; 812 813 Object object = rs.getObject(oldIndex); 814 815 if (object instanceof Entity) { 816 818 return object; 819 } 820 821 if (object == null) 822 return null; 823 824 switch (columnType) { 825 case Types.BIT: 826 case Types.BOOLEAN: 827 if (! (object instanceof Boolean )) 831 object = rs.getBoolean(oldIndex); 832 break; 834 835 case Types.TINYINT: 836 if (! (object instanceof Number )) 837 object = rs.getByte(oldIndex); 838 break; 839 840 case Types.SMALLINT: 841 if (! (object instanceof Number )) 842 object = rs.getShort(oldIndex); 843 break; 844 845 case Types.INTEGER: 846 if (! (object instanceof Number )) 847 object = rs.getLong(oldIndex); 848 break; 849 850 case Types.DECIMAL: 851 case Types.DOUBLE: 852 case Types.NUMERIC: 853 case Types.REAL: 854 if (! (object instanceof Number )) 855 object = rs.getDouble(oldIndex); 856 break; 857 858 case Types.FLOAT: 859 if (! (object instanceof Number )) 860 object = rs.getFloat(oldIndex); 861 break; 862 863 } 867 868 return object; 869 } 870 } 871 | Popular Tags |