1 package org.hibernate.impl; 3 4 import java.io.Serializable ; 5 import java.math.BigDecimal ; 6 import java.math.BigInteger ; 7 import java.util.ArrayList ; 8 import java.util.Arrays ; 9 import java.util.Calendar ; 10 import java.util.Collection ; 11 import java.util.Date ; 12 import java.util.HashMap ; 13 import java.util.HashSet ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 import java.util.Locale ; 17 import java.util.Map ; 18 import java.util.Set ; 19 import java.util.StringTokenizer ; 20 21 import org.hibernate.CacheMode; 22 import org.hibernate.FlushMode; 23 import org.hibernate.Hibernate; 24 import org.hibernate.HibernateException; 25 import org.hibernate.MappingException; 26 import org.hibernate.NonUniqueResultException; 27 import org.hibernate.PropertyNotFoundException; 28 import org.hibernate.Query; 29 import org.hibernate.QueryException; 30 import org.hibernate.engine.QueryParameters; 31 import org.hibernate.engine.RowSelection; 32 import org.hibernate.engine.SessionImplementor; 33 import org.hibernate.engine.TypedValue; 34 import org.hibernate.hql.classic.ParserHelper; 35 import org.hibernate.property.Getter; 36 import org.hibernate.proxy.HibernateProxyHelper; 37 import org.hibernate.type.SerializableType; 38 import org.hibernate.type.Type; 39 import org.hibernate.type.TypeFactory; 40 import org.hibernate.util.ArrayHelper; 41 import org.hibernate.util.MarkerObject; 42 import org.hibernate.util.ReflectHelper; 43 import org.hibernate.util.StringHelper; 44 45 49 public abstract class AbstractQueryImpl implements Query { 50 51 private static final Object UNSET_PARAMETER = new MarkerObject("<unset parameter>"); 52 private static final Object UNSET_TYPE = new MarkerObject("<unset type>"); 53 54 private String queryString; 55 protected final SessionImplementor session; 56 57 private RowSelection selection; 58 private List values = new ArrayList (4); 59 private List types = new ArrayList (4); 60 private int positionalParameterCount = 0; 61 private Set actualNamedParameters = new HashSet (4); 62 private Map namedParameters = new HashMap (4); 63 private Map namedParameterLists = new HashMap (4); 64 private boolean cacheable; 65 private String cacheRegion; 66 private String comment; 67 private FlushMode flushMode; 68 private CacheMode cacheMode; 69 private FlushMode sessionFlushMode; 70 private CacheMode sessionCacheMode; 71 private Serializable collectionKey; 72 private boolean readOnly; 73 74 public AbstractQueryImpl(String queryString, FlushMode flushMode, SessionImplementor session) { 75 this.session = session; 76 this.queryString = queryString; 77 this.selection = new RowSelection(); 78 this.flushMode = flushMode; 79 this.cacheMode = null; 80 initParameterBookKeeping(); 81 } 82 83 public final String getQueryString() { 84 return queryString; 85 } 86 87 public Query setFlushMode(FlushMode flushMode) { 88 this.flushMode = flushMode; 89 return this; 90 } 91 92 public Query setCacheMode(CacheMode cacheMode) { 93 this.cacheMode = cacheMode; 94 return this; 95 } 96 97 protected Map getNamedParams() { 98 return new HashMap (namedParameters); 99 } 100 101 protected void verifyParameters() throws QueryException { 102 verifyParameters(false); 103 } 104 105 109 protected void verifyParameters(boolean reserveFirstParameter) throws HibernateException { 110 111 if ( actualNamedParameters.size() != namedParameters.size() + namedParameterLists.size() ) { 112 Set missingParams = new HashSet (actualNamedParameters); 113 missingParams.removeAll( namedParameterLists.keySet() ); 114 missingParams.removeAll( namedParameters.keySet() ); 115 throw new QueryException( "Not all named parameters have been set: " + missingParams, getQueryString() ); 116 } 117 118 int positionalValueSpan = 0; 119 for ( int i=0; i<values.size(); i++ ) { 120 Object object = types.get(i); 121 if( values.get(i)==UNSET_PARAMETER || object==UNSET_TYPE ) { 122 if(reserveFirstParameter && i==0) { 123 continue; 124 } 125 else { 126 throw new QueryException( "Unset positional parameter at position: " + i, getQueryString() ); 127 } 128 } 129 positionalValueSpan += ( (Type) object ).getColumnSpan( session.getFactory() ); 130 } 131 132 if ( positionalParameterCount!=positionalValueSpan ) { 133 if(reserveFirstParameter && positionalParameterCount-1!=positionalValueSpan) { 134 throw new QueryException( 135 "Expected positional parameter count: " + 136 (positionalParameterCount-1) + 137 ", actual parameters: " + 138 values, 139 getQueryString() 140 ); 141 } 142 else if (!reserveFirstParameter) { 143 throw new QueryException( 144 "Expected positional parameter count: " + 145 positionalParameterCount + 146 ", actual parameters: " + 147 values, 148 getQueryString() 149 ); 150 } 151 } 152 } 153 154 protected Map getNamedParameterLists() { 155 return namedParameterLists; 156 } 157 158 protected List getValues() { 159 return values; 160 } 161 162 protected List getTypes() { 163 return types; 164 } 165 166 public RowSelection getSelection() { 168 return selection; 169 } 170 171 public Query setMaxResults(int maxResults) { 172 selection.setMaxRows( new Integer (maxResults) ); 173 return this; 174 } 175 176 public Query setTimeout(int timeout) { 177 selection.setTimeout( new Integer (timeout) ); 178 return this; 179 } 180 public Query setFetchSize(int fetchSize) { 181 selection.setFetchSize( new Integer (fetchSize) ); 182 return this; 183 } 184 185 186 public Query setFirstResult(int firstResult) { 187 selection.setFirstRow( new Integer (firstResult) ); 188 return this; 189 } 190 191 public Query setParameter(int position, Object val, Type type) { 192 if ( positionalParameterCount==0 ) { 193 throw new IllegalArgumentException ("No positional parameters in query: " + getQueryString() ); 194 } 195 if ( position<0 || position>positionalParameterCount-1 ) { 196 throw new IllegalArgumentException ("Positional parameter does not exist: " + position + " in query: " + getQueryString() ); 197 } 198 int size = values.size(); 199 if ( position<size ) { 200 values.set(position, val); 201 types.set(position, type); 202 } 203 else { 204 for ( int i=0; i<position-size; i++ ) { 206 values.add(UNSET_PARAMETER); 207 types.add(UNSET_TYPE); 208 } 209 values.add(val); 210 types.add(type); 211 } 212 return this; 213 } 214 215 public Query setString(int position, String val) { 216 setParameter(position, val, Hibernate.STRING); 217 return this; 218 } 219 220 public Query setCharacter(int position, char val) { 221 setParameter(position, new Character (val), Hibernate.CHARACTER); 222 return this; 223 } 224 225 public Query setBoolean(int position, boolean val) { 226 setParameter(position, val ? Boolean.TRUE : Boolean.FALSE, Hibernate.BOOLEAN); 227 return this; 228 } 229 230 public Query setByte(int position, byte val) { 231 setParameter(position, new Byte (val), Hibernate.BYTE); 232 return this; 233 } 234 235 public Query setShort(int position, short val) { 236 setParameter(position, new Short (val), Hibernate.SHORT); 237 return this; 238 } 239 240 public Query setInteger(int position, int val) { 241 setParameter(position, new Integer (val), Hibernate.INTEGER); 242 return this; 243 } 244 245 public Query setLong(int position, long val) { 246 setParameter(position, new Long (val), Hibernate.LONG); 247 return this; 248 } 249 250 public Query setFloat(int position, float val) { 251 setParameter(position, new Float (val), Hibernate.FLOAT); 252 return this; 253 } 254 255 public Query setDouble(int position, double val) { 256 setParameter(position, new Double (val), Hibernate.DOUBLE); 257 return this; 258 } 259 260 public Query setBinary(int position, byte[] val) { 261 setParameter(position, val, Hibernate.BINARY); 262 return this; 263 } 264 265 public Query setText(int position, String val) { 266 setParameter(position, val, Hibernate.TEXT); 267 return this; 268 } 269 270 public Query setSerializable(int position, Serializable val) { 271 setParameter(position, val, Hibernate.SERIALIZABLE); 272 return this; 273 } 274 275 public Query setDate(int position, Date date) { 276 setParameter(position, date, Hibernate.DATE); 277 return this; 278 } 279 280 public Query setTime(int position, Date date) { 281 setParameter(position, date, Hibernate.TIME); 282 return this; 283 } 284 285 public Query setTimestamp(int position, Date date) { 286 setParameter(position, date, Hibernate.TIMESTAMP); 287 return this; 288 } 289 290 public Query setEntity(int position, Object val) { 291 setParameter( position, val, Hibernate.entity( session.bestGuessEntityName(val) ) ); 292 return this; 293 } 294 295 public Query setLocale(int position, Locale locale) { 296 setParameter(position, locale, Hibernate.LOCALE); 297 return this; 298 } 299 300 public Query setCalendar(int position, Calendar calendar) { 301 setParameter(position, calendar, Hibernate.CALENDAR); 302 return this; 303 } 304 305 public Query setCalendarDate(int position, Calendar calendar) { 306 setParameter(position, calendar, Hibernate.CALENDAR_DATE); 307 return this; 308 } 309 310 public Query setBinary(String name, byte[] val) { 311 setParameter(name, val, Hibernate.BINARY); 312 return this; 313 } 314 315 public Query setText(String name, String val) { 316 setParameter(name, val, Hibernate.TEXT); 317 return this; 318 } 319 320 public Query setBoolean(String name, boolean val) { 321 setParameter(name, val ? Boolean.TRUE : Boolean.FALSE, Hibernate.BOOLEAN); 322 return this; 323 } 324 325 public Query setByte(String name, byte val) { 326 setParameter(name, new Byte (val), Hibernate.BYTE); 327 return this; 328 } 329 330 public Query setCharacter(String name, char val) { 331 setParameter(name, new Character (val), Hibernate.CHARACTER); 332 return this; 333 } 334 335 public Query setDate(String name, Date date) { 336 setParameter(name, date, Hibernate.DATE); 337 return this; 338 } 339 340 public Query setDouble(String name, double val) { 341 setParameter(name, new Double (val), Hibernate.DOUBLE); 342 return this; 343 } 344 345 public Query setEntity(String name, Object val) { 346 setParameter( name, val, Hibernate.entity( session.bestGuessEntityName(val) ) ); 347 return this; 348 } 349 350 public Query setFloat(String name, float val) { 351 setParameter(name, new Float (val), Hibernate.FLOAT); 352 return this; 353 } 354 355 public Query setInteger(String name, int val) { 356 setParameter(name, new Integer (val), Hibernate.INTEGER); 357 return this; 358 } 359 360 public Query setLocale(String name, Locale locale) { 361 setParameter(name, locale, Hibernate.LOCALE); 362 return this; 363 } 364 365 public Query setCalendar(String name, Calendar calendar) { 366 setParameter(name, calendar, Hibernate.CALENDAR); 367 return this; 368 } 369 370 public Query setCalendarDate(String name, Calendar calendar) { 371 setParameter(name, calendar, Hibernate.CALENDAR_DATE); 372 return this; 373 } 374 375 public Query setLong(String name, long val) { 376 setParameter(name, new Long (val), Hibernate.LONG); 377 return this; 378 } 379 380 public Query setParameter(String name, Object val, Type type) { 381 if( !actualNamedParameters.contains(name) ) { 382 throw new IllegalArgumentException ("Parameter " + name + " does not exist as a named parameter in [" + getQueryString() + "]"); 383 } 384 else { 385 namedParameters.put( name, new TypedValue( type, val, session.getEntityMode() ) ); 386 return this; 387 } 388 } 389 390 public Query setSerializable(String name, Serializable val) { 391 setParameter(name, val, Hibernate.SERIALIZABLE); 392 return this; 393 } 394 395 public Query setShort(String name, short val) { 396 setParameter(name, new Short (val), Hibernate.SHORT); 397 return this; 398 } 399 400 public Query setString(String name, String val) { 401 setParameter(name, val, Hibernate.STRING); 402 return this; 403 } 404 405 public Query setTime(String name, Date date) { 406 setParameter(name, date, Hibernate.TIME); 407 return this; 408 } 409 410 public Query setTimestamp(String name, Date date) { 411 setParameter(name, date, Hibernate.TIMESTAMP); 412 return this; 413 } 414 415 public Query setBigDecimal(int position, BigDecimal number) { 416 setParameter(position, number, Hibernate.BIG_DECIMAL); 417 return this; 418 } 419 420 public Query setBigDecimal(String name, BigDecimal number) { 421 setParameter(name, number, Hibernate.BIG_DECIMAL); 422 return this; 423 } 424 425 public Query setBigInteger(int position, BigInteger number) { 426 setParameter(position, number, Hibernate.BIG_DECIMAL); 427 return this; 428 } 429 430 public Query setBigInteger(String name, BigInteger number) { 431 setParameter(name, number, Hibernate.BIG_DECIMAL); 432 return this; 433 } 434 435 public Query setParameter(int position, Object val) throws HibernateException { 436 if (val == null) { 437 setParameter( position, val, Hibernate.SERIALIZABLE ); 438 } 439 else { 440 setParameter( position, val, guessType(val) ); 441 } 442 return this; 443 } 444 445 public Query setParameter(String name, Object val) throws HibernateException { 446 if (val == null) { 447 setParameter( name, val, Hibernate.SERIALIZABLE ); 448 } 449 else { 450 setParameter( name, val, guessType(val) ); 451 } 452 return this; 453 } 454 455 private Type guessType(Object param) throws HibernateException { 456 Class clazz = HibernateProxyHelper.getClassWithoutInitializingProxy(param); 457 return guessType(clazz); 458 } 459 460 private Type guessType(Class clazz) throws HibernateException { 461 String typename = clazz.getName(); 462 Type type = TypeFactory.heuristicType(typename); 463 boolean serializable = type!=null && type instanceof SerializableType; 464 if (type==null || serializable) { 465 try { 466 session.getFactory().getEntityPersister( clazz.getName() ); 467 } 468 catch (MappingException me) { 469 if (serializable) { 470 return type; 471 } 472 else { 473 throw new HibernateException("Could not determine a type for class: " + typename); 474 } 475 } 476 return Hibernate.entity(clazz); 477 } 478 else { 479 return type; 480 } 481 } 482 483 484 public Type[] getReturnTypes() throws HibernateException { 485 return session.getFactory().getReturnTypes( queryString ); 486 } 487 488 public String [] getReturnAliases() throws HibernateException { 489 return session.getFactory().getReturnAliases( queryString ); 490 } 491 492 public Query setParameterList(String name, Collection vals, Type type) throws HibernateException { 493 if( !actualNamedParameters.contains(name) ) { 494 throw new IllegalArgumentException ("Parameter " + name + " does not exist as a named parameter in [" + getQueryString() + "]"); 495 } 496 namedParameterLists.put( name, new TypedValue( type, vals, session.getEntityMode() ) ); 497 return this; 498 } 499 500 503 protected String bindParameterLists(Map namedParamsCopy) { 504 String query = this.queryString; 505 Iterator iter = namedParameterLists.entrySet().iterator(); 506 while ( iter.hasNext() ) { 507 Map.Entry me = (Map.Entry ) iter.next(); 508 query = bindParameterList( query, (String ) me.getKey(), (TypedValue) me.getValue(), namedParamsCopy ); 509 } 510 return query; 511 } 512 513 516 private String bindParameterList(String query, String name, TypedValue typedList, Map namedParamsCopy) { 517 Collection vals = (Collection ) typedList.getValue(); 518 Type type = typedList.getType(); 519 StringBuffer list = new StringBuffer (16); 520 Iterator iter = vals.iterator(); 521 int i=0; 522 while ( iter.hasNext() ) { 523 String alias = name + i++ + '_'; 524 namedParamsCopy.put(alias, new TypedValue( type, iter.next(), session.getEntityMode() ) ); 525 list.append( ParserHelper.HQL_VARIABLE_PREFIX + alias ); 526 if ( iter.hasNext() ) list.append(", "); 527 } 528 return StringHelper.replace( query, ParserHelper.HQL_VARIABLE_PREFIX + name, list.toString(), true ); 529 } 530 531 public Query setParameterList(String name, Collection vals) throws HibernateException { 532 if (vals==null) { 533 throw new QueryException("Collection must be not null!"); 534 } 535 536 if(vals.size()==0) { 537 setParameterList(name, vals, null); 538 } 539 else { 540 setParameterList(name, vals, guessType( vals.iterator().next() ) ); 541 } 542 543 return this; 544 } 545 546 public String [] getNamedParameters() throws HibernateException { 547 return (String []) actualNamedParameters.toArray(new String [actualNamedParameters.size()]); 548 } 549 550 private void initParameterBookKeeping() { 551 StringTokenizer st = new StringTokenizer (queryString, ParserHelper.HQL_SEPARATORS); 552 Set result = new HashSet (); 553 554 while ( st.hasMoreTokens() ) { 555 String string = st.nextToken(); 556 if( string.startsWith(ParserHelper.HQL_VARIABLE_PREFIX) ) { 557 result.add( string.substring(1) ); 558 } 559 } 560 561 actualNamedParameters = result; 562 563 int[] positions = StringHelper.locateUnquoted( queryString, '?' ); 568 int queryStringLength = queryString.length(); 569 570 for ( int i = 0; i < positions.length; i++ ) { 571 String ejb3PositionalParam = ""; 575 for ( int peekPosition = positions[i] + 1; 576 peekPosition < queryStringLength && Character.isDigit( queryString.charAt( peekPosition ) ); 577 peekPosition++ ) { 578 ejb3PositionalParam += queryString.charAt( peekPosition ); 579 } 580 581 if ( "".equals( ejb3PositionalParam ) ) { 582 positionalParameterCount++; 583 } 584 else { 585 actualNamedParameters.add( ejb3PositionalParam ); 586 } 587 } 588 } 589 590 public Query setProperties(Object bean) throws HibernateException { 591 Class clazz = bean.getClass(); 592 String [] params = getNamedParameters(); 593 for (int i = 0; i < params.length; i++) { 594 String namedParam = params[i]; 595 try { 596 Getter getter = ReflectHelper.getGetter(clazz, namedParam); 597 Class retType = getter.getReturnType(); 598 final Object object = getter.get( bean ); 599 if ( Collection .class.isAssignableFrom(retType) ) { 600 setParameterList( namedParam, (Collection ) object ); 601 } 602 else if ( retType.isArray() ) { 603 setParameterList( namedParam, (Object []) object ); 604 } 605 else { 606 setParameter( namedParam, object, guessType( getter.getReturnType() ) ); 607 } 608 } 609 catch (PropertyNotFoundException pnfe) {} 610 } 611 return this; 612 } 613 614 615 public Query setParameterList(String name, Object [] vals, Type type) 616 throws HibernateException { 617 return setParameterList(name, Arrays.asList(vals), type); 618 } 619 620 public Query setParameterList(String name, Object [] vals) 621 throws HibernateException { 622 return setParameterList( name, Arrays.asList(vals) ); 623 } 624 625 SessionImplementor getSession() { 626 return session; 627 } 628 629 public Object uniqueResult() throws HibernateException { 630 return uniqueElement( list() ); 631 } 632 633 public int executeUpdate() throws HibernateException { 634 throw new UnsupportedOperationException ( "Update queries only supported through HQL" ); 635 } 636 637 static Object uniqueElement(List list) throws NonUniqueResultException { 638 int size = list.size(); 639 if (size==0) return null; 640 Object first = list.get(0); 641 for ( int i=1; i<size; i++ ) { 642 if ( list.get(i)!=first ) { 643 throw new NonUniqueResultException( list.size() ); 644 } 645 } 646 return first; 647 } 648 649 protected RowSelection getRowSelection() { 650 return selection; 651 } 652 653 public Type[] typeArray() { 654 return ArrayHelper.toTypeArray( getTypes() ); 655 } 656 657 public Object [] valueArray() { 658 return getValues().toArray(); 659 } 660 661 public QueryParameters getQueryParameters(Map namedParams) { 662 return new QueryParameters( 663 typeArray(), 664 valueArray(), 665 namedParams, 666 getLockModes(), 667 getSelection(), 668 readOnly, 669 cacheable, 670 cacheRegion, 671 comment, 673 collectionKey==null ? 674 null : 675 new Serializable [] { collectionKey } 676 ); 677 } 678 679 protected abstract Map getLockModes(); 680 681 public Query setCacheable(boolean cacheable) { 682 this.cacheable = cacheable; 683 return this; 684 } 685 686 public Query setCacheRegion(String cacheRegion) { 687 if (cacheRegion != null) 688 this.cacheRegion = cacheRegion.trim(); 689 return this; 690 } 691 692 public Query setComment(String comment) { 693 this.comment = comment; 694 return this; 695 } 696 697 public String toString() { 698 return StringHelper.unqualify( getClass().getName() ) + '(' + queryString + ')'; 699 } 700 701 protected void before() { 702 if ( flushMode!=null ) { 703 sessionFlushMode = getSession().getFlushMode(); 704 getSession().setFlushMode(flushMode); 705 } 706 if ( cacheMode!=null ) { 707 sessionCacheMode = getSession().getCacheMode(); 708 getSession().setCacheMode(cacheMode); 709 } 710 } 711 712 protected void after() { 713 if (sessionFlushMode!=null) { 714 getSession().setFlushMode(sessionFlushMode); 715 sessionFlushMode = null; 716 } 717 if (sessionCacheMode!=null) { 718 getSession().setCacheMode(sessionCacheMode); 719 sessionCacheMode = null; 720 } 721 } 722 723 public Query setCollectionKey(Serializable collectionKey) { 724 this.collectionKey = collectionKey; 725 return this; 726 } 727 728 public Query setParameters(Object [] values, Type[] types) { 729 this.values = Arrays.asList(values); 730 this.types = Arrays.asList(types); 731 return this; 732 } 733 734 public boolean isReadOnly() { 735 return readOnly; 736 } 737 738 public Query setReadOnly(boolean readOnly) { 739 this.readOnly = readOnly; 740 return this; 741 } 742 } 743 | Popular Tags |