1 package org.hibernate.test.hql; 3 4 import java.sql.Connection ; 5 import java.sql.ParameterMetaData ; 6 import java.sql.PreparedStatement ; 7 import java.sql.ResultSet ; 8 import java.sql.ResultSetMetaData ; 9 import java.sql.SQLException ; 10 import java.util.Collections ; 11 import java.util.HashMap ; 12 import java.util.Iterator ; 13 import java.util.Map ; 14 import java.util.Set ; 15 import java.util.StringTokenizer ; 16 import java.util.TreeMap ; 17 18 import junit.framework.ComparisonFailure; 19 20 import org.hibernate.EntityMode; 21 import org.hibernate.MappingException; 22 import org.hibernate.QueryException; 23 import org.hibernate.classic.Session; 24 import org.hibernate.engine.SessionFactoryImplementor; 25 import org.hibernate.hql.QueryTranslator; 26 import org.hibernate.hql.QueryTranslatorFactory; 27 import org.hibernate.hql.ast.ASTQueryTranslatorFactory; 28 import org.hibernate.hql.ast.HqlToken; 29 import org.hibernate.hql.ast.util.ASTPrinter; 30 import org.hibernate.hql.classic.ClassicQueryTranslatorFactory; 31 import org.hibernate.test.TestCase; 32 import org.hibernate.type.Type; 33 import org.hibernate.type.TypeFactory; 34 import org.hibernate.util.StringHelper; 35 36 41 public abstract class QueryTranslatorTestCase extends TestCase { 42 public QueryTranslatorTestCase(String x) { 43 super( x ); 44 new HqlToken(); 47 } 48 49 public void assertTranslation(String hql) throws QueryException, MappingException { 50 assertTranslation( hql, null ); 51 } 52 53 public void assertTranslation(String hql, boolean scalar) throws QueryException, MappingException { 54 assertTranslation( hql, null, scalar, null ); 55 } 56 57 protected void assertTranslation(String hql, HashMap replacements) { 58 ComparisonFailure cf = null; 59 try { 60 assertTranslation( hql, replacements, false, null ); 61 } 62 catch ( ComparisonFailure e ) { 63 e.printStackTrace(); 64 cf = e; 65 } 66 if ("false".equals(System.getProperty("org.hibernate.test.hql.SkipScalarQuery","false"))) { 67 assertTranslation( hql, replacements, true, null ); 69 } 70 if (cf != null) 71 throw cf; 72 } 73 74 protected void runClassicTranslator(String hql) throws Exception { 75 SessionFactoryImplementor factory = getSessionFactoryImplementor(); 76 Map replacements = new HashMap (); 77 QueryTranslator oldQueryTranslator = null; 78 try { 79 QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory(); 80 oldQueryTranslator = classic.createQueryTranslator( hql, Collections.EMPTY_MAP, factory ); 81 oldQueryTranslator.compile( replacements, false ); 82 } 83 catch ( Exception e ) { 84 e.printStackTrace(); 85 throw e; 86 } 87 String oldsql = oldQueryTranslator.getSQLString(); 88 System.out.println( "HQL : " + hql ); 89 System.out.println( "OLD SQL: " + oldsql ); 90 } 91 92 protected void assertTranslation(String hql, HashMap replacements, boolean scalar, String sql) { 93 SessionFactoryImplementor factory = getSessionFactoryImplementor(); 94 95 if ( replacements == null ) { 97 replacements = new HashMap (); 98 } 99 100 QueryTranslator oldQueryTranslator = null; 102 Exception oldException = null; 103 try { 104 System.out.println("Compiling with classic QueryTranslator..."); 105 QueryTranslatorFactory classic = new ClassicQueryTranslatorFactory(); 106 oldQueryTranslator = classic.createQueryTranslator( hql, Collections.EMPTY_MAP, factory ); 107 oldQueryTranslator.compile( replacements, scalar ); 108 } 109 catch ( QueryException e ) { 110 oldException = e; 111 } 112 catch ( MappingException e ) { 113 oldException = e; 114 } 115 116 QueryTranslator newQueryTranslator = null; 117 Exception newException = null; 118 try { 119 System.out.println("Compiling with AST QueryTranslator..."); 120 QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); 121 newQueryTranslator = ast.createQueryTranslator( hql, Collections.EMPTY_MAP, factory ); 122 newQueryTranslator.compile( replacements, scalar ); 123 } 124 catch ( QueryException e ) { 125 newException = e; 126 } 127 catch ( MappingException e ) { 128 newException = e; 129 } 130 131 if ( oldException != null ) { 133 assertNotNull( "New query translator did *NOT* throw an exception, the old one did : " + oldException, newException ); 135 assertEquals( oldException.getMessage(), newException.getMessage() ); 136 return; } 138 else if ( newException != null ) { 139 newException.printStackTrace(); 140 assertNull( "Old query translator did not throw an exception, the new one did", newException ); 141 } 142 143 checkSql( oldQueryTranslator, newQueryTranslator, hql, scalar, sql ); 145 checkQuerySpaces( oldQueryTranslator, newQueryTranslator ); 146 checkReturnedTypes( oldQueryTranslator, newQueryTranslator ); 147 checkColumnNames( oldQueryTranslator, newQueryTranslator ); 148 149 } 150 151 protected SessionFactoryImplementor getSessionFactoryImplementor() { 152 SessionFactoryImplementor factory = ( SessionFactoryImplementor ) getSessions(); 153 if ( factory == null ) { 154 throw new NullPointerException ( "Unable to create factory!" ); 155 } 156 return factory; 157 } 158 159 private void checkColumnNames(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) { 160 162 String [][] oldColumnNames = oldQueryTranslator.getColumnNames(); 163 String [][] newColumnNames = newQueryTranslator.getColumnNames(); 164 171 } 172 173 private void checkReturnedTypes(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) { 174 Type[] oldReturnTypes = oldQueryTranslator.getReturnTypes(); 176 Type[] returnTypes = newQueryTranslator.getReturnTypes(); 177 assertEquals( "Return types array is not the right length!", oldReturnTypes.length, returnTypes.length ); 178 for ( int i = 0; i < returnTypes.length; i++ ) { 179 assertNotNull( returnTypes[i] ); 180 assertNotNull( oldReturnTypes[i] ); 181 assertEquals( "Returned types did not match!", oldReturnTypes[i].getReturnedClass(), returnTypes[i].getReturnedClass() ); 182 System.out.println("returnedType[" + i + "] = " + returnTypes[i] + " oldReturnTypes[" + i + "] = " + oldReturnTypes[i]); 183 } 184 } 185 186 private void checkQuerySpaces(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator) { 187 Set oldQuerySpaces = oldQueryTranslator.getQuerySpaces(); 189 Set querySpaces = newQueryTranslator.getQuerySpaces(); 190 assertEquals( "Query spaces is not the right size!", oldQuerySpaces.size(), querySpaces.size() ); 191 for ( Iterator iterator = oldQuerySpaces.iterator(); iterator.hasNext(); ) { 192 Object o = iterator.next(); 193 assertTrue( "New query space does not contain " + o + "!", querySpaces.contains( o ) ); 194 } 195 } 196 197 protected Exception compileBadHql(String hql, boolean scalar) { 198 QueryTranslator newQueryTranslator; 199 Map replacements = null; 200 Exception newException = null; 201 SessionFactoryImplementor factory = getSessionFactoryImplementor(); 202 try { 203 QueryTranslatorFactory ast = new ASTQueryTranslatorFactory(); 204 newQueryTranslator = ast.createQueryTranslator( hql, Collections.EMPTY_MAP, factory ); 205 newQueryTranslator.compile( replacements, scalar ); 206 } 207 catch ( QueryException e ) { 208 newException = e; 209 } 210 catch ( MappingException e ) { 211 newException = e; 212 } 213 assertNotNull( "Expected exception from compilation of '" + hql + "'!", newException ); 214 return newException; 215 } 216 217 private void checkSql(QueryTranslator oldQueryTranslator, QueryTranslator newQueryTranslator, String hql, boolean scalar, String sql) { 218 219 String oldsql = oldQueryTranslator.getSQLString(); 220 String newsql = newQueryTranslator.getSQLString(); 221 System.out.println( "HQL : " + ASTPrinter.escapeMultibyteChars(hql) ); 222 System.out.println( "OLD SQL: " + ASTPrinter.escapeMultibyteChars(oldsql) ); 223 System.out.println( "NEW SQL: " + ASTPrinter.escapeMultibyteChars(newsql) ); 224 if ( sql == null ) { 225 assertSQLEquals( "SQL is not the same as the old SQL (scalar=" + scalar + ")", oldsql, newsql ); 227 } 228 else { 229 assertSQLEquals( "SQL is not the same as the expected SQL (scalar=" + scalar + ")", sql, newsql ); 230 } 231 } 232 233 private void assertSQLEquals(String message, String oldsql, String newsql) { 234 Map oldMap = getTokens(oldsql); 235 Map newMap = getTokens(newsql); 236 if ( !oldMap.equals(newMap) ) { 237 assertEquals(message, oldsql, newsql); 238 } 239 240 } 244 245 246 private Map getTokens(String sql) { 247 Map result = new TreeMap (); 248 if (sql==null) return result; 249 result.put( "=", new Integer ( StringHelper.countUnquoted(sql, '=') ) ); 250 StringTokenizer tokenizer = new StringTokenizer ( sql, "(),= " ); 251 while ( tokenizer.hasMoreTokens() ) { 252 String fragment = tokenizer.nextToken(); 253 255 Integer count = (Integer ) result.get(fragment); 256 if ( count==null ) { 257 count = new Integer (1); 258 } 259 else { 260 count = new Integer ( count.intValue() + 1 ); 261 } 262 result.put(fragment, count); 263 } 264 return result; 265 } 266 267 private String stripExtraSpaces(String string) { 268 if ( string == null ) { 269 return null; 270 } 271 272 StringBuffer buffer = new StringBuffer ( string.length() ); 273 char[] chars = string.toCharArray(); 274 int length = chars.length; 275 boolean wasSpace = false; 276 for ( int i = 0; i < length; i++ ) { 277 boolean isSpace = chars[i] == ' '; 278 if ( wasSpace && isSpace ) { 279 continue; 280 } 281 else { 282 buffer.append( chars[i] ); 283 } 284 285 wasSpace = isSpace; 286 } 287 return buffer.toString(); 295 } 296 297 private void checkSqlByResultSet( 298 QueryTranslator oldQueryTranslator, 299 QueryTranslator newQueryTranslator, 300 Object [] binds 301 ) { 302 String oldsql = oldQueryTranslator.getSQLString(); 303 String newsql = newQueryTranslator.getSQLString(); 304 305 Session session = openSession(); 306 Connection connection = session.connection(); 307 308 PreparedStatement oldps = null; 309 PreparedStatement newps = null; 310 ResultSet oldrs = null; 311 ResultSet newrs = null; 312 313 try { 314 try { 315 oldps = connection.prepareStatement( oldsql ); 316 } 317 catch( Throwable t ) { 318 fail( "Unable to prepare sql generated by old parser : " + t ); 319 } 320 try { 321 newps = connection.prepareStatement( newsql ); 322 } 323 catch( Throwable t ) { 324 fail( "Unable to prepare sql generated by new parser : " + t ); 325 } 326 327 checkBinds(oldps, newps, binds); 328 329 try { 330 oldrs = executeQuery( oldps, binds ); 331 } 332 catch( Throwable t ) { 333 fail( "Unable to execute sql generated by old parser : " + t ); 334 } 335 336 try { 337 newrs = executeQuery( newps, binds ); 338 } 339 catch( Throwable t ) { 340 fail( "Unable to execute sql generated by new parser : " + t ); 341 } 342 343 checkResults( oldrs, newrs ); 344 } 345 finally { 346 release(oldrs); 348 release(newrs); 349 release(oldps); 350 release(newps); 351 release(session); 352 } 353 } 354 355 private void checkBinds(PreparedStatement oldps, PreparedStatement newps, Object [] binds) { 356 try { 358 ParameterMetaData oldBindMetaData = oldps.getParameterMetaData(); 359 ParameterMetaData newBindMetaData = newps.getParameterMetaData(); 360 361 assertEquals( "Different bind parameter count", oldBindMetaData.getParameterCount(), newBindMetaData.getParameterCount() ); 362 assertEquals( "Incorrect number of binds passed in", oldBindMetaData.getParameterCount(), binds == null ? 0 : binds.length ); 363 364 for ( int i = 0, max = oldBindMetaData.getParameterCount(); i < max; i++ ) { 365 assertEquals( "Different bind types", oldBindMetaData.getParameterType(i), newBindMetaData.getParameterType(i) ); 366 } 367 } 368 catch( Throwable t ) { 369 fail( "SQLException comparing binds : " + t ); 370 } 371 } 372 373 private ResultSet executeQuery(PreparedStatement ps, Object [] binds) throws SQLException { 374 if ( binds != null ) { 375 for ( int i = 0, max = binds.length; i < max; i++ ) { 376 ps.setObject( i, binds[i] ); 377 } 378 } 379 380 return ps.executeQuery(); 381 } 382 383 private void checkResults(ResultSet oldrs, ResultSet newrs) { 384 ResultSetMetaData oldmeta = null; 385 ResultSetMetaData newmeta = null; 386 int colCount = 0; 387 Type[] types = null; 388 389 try { 391 oldmeta = oldrs.getMetaData(); 392 newmeta = newrs.getMetaData(); 393 assertEquals( "Different column counts", oldmeta.getColumnCount(), newmeta.getColumnCount() ); 394 395 colCount = oldmeta.getColumnCount(); 396 types = new Type[colCount]; 397 398 for ( int i = 1, max = colCount; i < max; i++ ) { 399 assertEquals( "Column names were different", oldmeta.getColumnName(i), newmeta.getColumnName(i) ); 400 assertEquals( "Column types were different", oldmeta.getColumnType(i), newmeta.getColumnType(i) ); 401 assertEquals( "Java types were different", oldmeta.getColumnClassName(i), newmeta.getColumnClassName(i) ); 402 types[i] = TypeFactory.basic( oldmeta.getColumnClassName(i) ); 403 } 404 } 405 catch( Throwable t ) { 406 fail( "Error comparing result set metadata" ); 407 } 408 409 try { 411 while ( oldrs.next() & newrs.next() ) { 412 for ( int i = 1; i < colCount; i++ ) { 413 Object oldval = oldrs.getObject(i); 414 if ( oldrs.wasNull() ) oldval = null; 415 Object newval = newrs.getObject(i); 416 if ( newrs.wasNull() ) newval = null; 417 checkLogicalEquality( oldval, newval, types[i] ); 418 } 419 } 420 421 while ( oldrs.next() ); 423 while ( newrs.next() ); 424 425 assertEquals( "Different row counts", oldrs.getRow(), newrs.getRow() ); 426 } 427 catch( Throwable t ) { 428 fail( "Error comparing result set structure" ); 429 } 430 } 431 432 private void checkLogicalEquality(Object oldval, Object newval, Type type) { 433 if ( oldval == null && newval == null ) { 434 return; 436 } 437 else { 438 assertTrue( "Different result values", type.isEqual(oldval, newval, EntityMode.POJO) ); 439 } 440 } 441 442 private void release(PreparedStatement ps) { 443 if ( ps != null ) { 444 try { 445 ps.close(); 446 } 447 catch( Throwable t ) {} 448 } 449 } 450 451 private void release(ResultSet rs) { 452 if ( rs != null ) { 453 try { 454 rs.close(); 455 } 456 catch( Throwable t ) {} 457 } 458 } 459 460 private void release(Session session) { 461 if ( session != null ) { 462 try { 463 session.close(); 464 } 465 catch( Throwable t ) {} 466 } 467 } 468 469 protected String [] getMappings() { 470 return new String []{ 471 "hql/Animal.hbm.xml", 472 "hql/EntityWithCrazyCompositeKey.hbm.xml", 473 "batchfetch/ProductLine.hbm.xml", 474 "cid/Customer.hbm.xml", 475 "cid/Order.hbm.xml", 476 "cid/LineItem.hbm.xml", 477 "cid/Product.hbm.xml", 478 "legacy/Baz.hbm.xml", 479 "legacy/Category.hbm.xml", 480 "legacy/Commento.hbm.xml", 481 "legacy/Container.hbm.xml", 482 "legacy/Custom.hbm.xml", 483 "legacy/Eye.hbm.xml", 484 "legacy/Fee.hbm.xml", 485 "legacy/FooBar.hbm.xml", 486 "legacy/Fum.hbm.xml", 487 "legacy/Glarch.hbm.xml", 488 "legacy/Holder.hbm.xml", 489 "legacy/Many.hbm.xml", 490 "legacy/Marelo.hbm.xml", 491 "legacy/MasterDetail.hbm.xml", 492 "legacy/Middle.hbm.xml", 493 "legacy/Multi.hbm.xml", 494 "legacy/Nameable.hbm.xml", 495 "legacy/One.hbm.xml", 496 "legacy/Qux.hbm.xml", 497 "legacy/Simple.hbm.xml", 498 "legacy/SingleSeveral.hbm.xml", 499 "legacy/WZ.hbm.xml", 500 "legacy/UpDown.hbm.xml", 501 "compositeelement/Parent.hbm.xml", 502 "onetoone/joined/Person.hbm.xml", 503 "hql/CrazyIdFieldNames.hbm.xml" 504 }; 505 } 506 507 protected boolean recreateSchema() { 508 return false; 510 } 511 } 512 | Popular Tags |