1 package org.hibernate.loader.custom; 3 4 import org.hibernate.QueryException; 5 import org.hibernate.hql.classic.ParserHelper; 6 import org.hibernate.persister.collection.SQLLoadableCollection; 7 import org.hibernate.persister.entity.SQLLoadable; 8 import org.hibernate.util.StringHelper; 9 10 import java.util.ArrayList ; 11 import java.util.Arrays ; 12 import java.util.HashMap ; 13 import java.util.List ; 14 import java.util.Map ; 15 16 19 public class SQLQueryParser { 20 21 private final String sqlQuery; 22 23 private final Map entityPersisterByAlias; 24 private final String [] aliases; 25 private final String [] suffixes; 26 27 private final SQLLoadableCollection[] collectionPersisters; 28 private final String [] collectionAliases; 29 private final String [] collectionSuffixes; 30 31 private int parameterCount = 0; 32 private final Map namedParameters = new HashMap (); 33 private final Map returnByAlias; 34 35 private long aliasesFound = 0; 36 public SQLQueryParser(String sqlQuery, 37 Map alias2Persister, 38 Map alias2Return, 39 String [] aliases, 40 String [] collectionAliases, 41 SQLLoadableCollection[] collectionPersisters, 42 String [] suffixes, 43 String [] collectionSuffixes) { 44 this.sqlQuery = sqlQuery; 45 this.entityPersisterByAlias = alias2Persister; 46 this.returnByAlias = alias2Return; this.collectionAliases = collectionAliases; 48 this.collectionPersisters = collectionPersisters; 49 this.suffixes = suffixes; 50 this.aliases = aliases; 51 this.collectionSuffixes = collectionSuffixes; 52 } 53 54 private SQLLoadable getPersisterByResultAlias(String aliasName) { 55 return (SQLLoadable) entityPersisterByAlias.get(aliasName); 56 } 57 58 private Map getPropertyResultByResultAlias(String aliasName) { 59 SQLQueryReturn sqr = (SQLQueryReturn) returnByAlias.get(aliasName); 60 return sqr.getPropertyResultsMap(); 61 } 62 63 private boolean isEntityAlias(String aliasName) { 64 return entityPersisterByAlias.containsKey(aliasName); 65 } 66 67 private int getPersisterIndex(String aliasName) { 68 for ( int i = 0; i < aliases.length; i++ ) { 69 if ( aliasName.equals( aliases[i] ) ) { 70 return i; 71 } 72 } 73 return -1; 74 } 75 76 public String process() { 77 return substituteParams( substituteBrackets() ); 78 } 79 80 private String substituteBrackets() throws QueryException { 83 84 StringBuffer result = new StringBuffer ( sqlQuery.length() + 20 ); 85 int left, right; 86 87 for ( int curr = 0; curr < sqlQuery.length(); curr = right + 1 ) { 89 if ( ( left = sqlQuery.indexOf( '{', curr ) ) < 0 ) { 90 result.append( sqlQuery.substring( curr ) ); 93 break; 94 } 95 96 result.append( sqlQuery.substring( curr, left ) ); 98 99 if ( ( right = sqlQuery.indexOf( '}', left + 1 ) ) < 0 ) { 100 throw new QueryException( "Unmatched braces for alias path", sqlQuery ); 101 } 102 103 String aliasPath = sqlQuery.substring( left + 1, right ); 104 int firstDot = aliasPath.indexOf( '.' ); 105 if ( firstDot == -1 ) { 106 if ( isEntityAlias(aliasPath) ) { 107 result.append(aliasPath); 109 aliasesFound++; 110 } 111 else { 112 result.append( '{' ).append(aliasPath).append( '}' ); 114 } 115 } 116 else { 117 String aliasName = aliasPath.substring(0, firstDot); 118 int collectionIndex = Arrays.binarySearch(collectionAliases, aliasName); 119 boolean isCollection = collectionIndex>-1; 120 boolean isEntity = isEntityAlias(aliasName); 121 122 if (isCollection) { 123 String propertyName = aliasPath.substring( firstDot + 1 ); 125 result.append(resolveCollectionProperties(aliasName, 126 propertyName, 127 getPropertyResultByResultAlias(aliasName), 128 getPersisterByResultAlias(aliasName), 129 collectionPersisters[collectionIndex], 130 collectionSuffixes[collectionIndex], 131 suffixes[getPersisterIndex(aliasName)]) ); 132 aliasesFound++; 133 } 134 else if (isEntity) { 135 String propertyName = aliasPath.substring( firstDot + 1 ); 137 result.append(resolveProperties( 138 aliasName, 139 propertyName, 140 getPropertyResultByResultAlias(aliasName), 141 getPersisterByResultAlias(aliasName), suffixes[getPersisterIndex(aliasName)] ) ); 143 aliasesFound++; 144 } 145 146 if ( !isEntity && !isCollection ) { 147 result.append( '{' ).append(aliasPath).append( '}' ); 149 } 150 151 } 152 } 153 154 156 return result.toString(); 157 } 158 159 private String resolveCollectionProperties(String aliasName, 160 String propertyName, 161 Map fieldResults, SQLLoadable elementPersister, SQLLoadableCollection currentPersister, String suffix, String persisterSuffix) { 162 163 if ( "*".equals( propertyName ) ) { 164 if( !fieldResults.isEmpty() ) { 165 throw new QueryException("Using return-propertys together with * syntax is not supported."); 166 } 167 168 String selectFragment = currentPersister.selectFragment( aliasName, suffix ); 169 aliasesFound++; 170 return new String (selectFragment 171 + ", " 172 + resolveProperties(aliasName, propertyName, fieldResults, elementPersister, persisterSuffix ) ); 173 } 174 else if ( "element.*".equals( propertyName ) ) { 175 return resolveProperties(aliasName, "*", fieldResults, elementPersister, persisterSuffix); 176 177 } 178 else { 179 180 String [] columnAliases; 181 182 columnAliases = (String []) fieldResults.get(propertyName); 184 if(columnAliases==null) { 185 columnAliases = currentPersister.getCollectionPropertyColumnAliases( propertyName, suffix ); 186 } 187 188 if ( columnAliases == null || columnAliases.length == 0 ) { 189 throw new QueryException( "No column name found for property [" + 190 propertyName + 191 "] for alias [" + aliasName + "]", 192 sqlQuery ); 193 } 194 if ( columnAliases.length != 1 ) { 195 throw new QueryException( "SQL queries only support properties mapped to a single column - property [" + 197 propertyName + 198 "] is mapped to " + 199 columnAliases.length + 200 " columns.", 201 sqlQuery ); 202 } 203 aliasesFound++; 204 return columnAliases[0]; 205 206 } 207 } 208 private String resolveProperties(String aliasName, 209 String propertyName, 210 Map fieldResults, SQLLoadable currentPersister, String suffix) { 211 220 221 if ( "*".equals( propertyName ) ) { 222 if( !fieldResults.isEmpty() ) { 223 throw new QueryException("Using return-propertys together with * syntax is not supported."); 224 } 225 aliasesFound++; 226 return currentPersister.selectFragment( aliasName, suffix ) ; 227 } 228 else { 229 230 String [] columnAliases; 231 232 columnAliases = (String []) fieldResults.get(propertyName); 234 if(columnAliases==null) { 235 columnAliases = currentPersister.getSubclassPropertyColumnAliases( propertyName, suffix ); 236 } 237 238 if ( columnAliases == null || columnAliases.length == 0 ) { 239 throw new QueryException( "No column name found for property [" + 240 propertyName + 241 "] for alias [" + aliasName + "]", 242 sqlQuery ); 243 } 244 if ( columnAliases.length != 1 ) { 245 throw new QueryException( "SQL queries only support properties mapped to a single column - property [" + 247 propertyName + 248 "] is mapped to " + 249 columnAliases.length + 250 " columns.", 251 sqlQuery ); 252 } 253 aliasesFound++; 254 return columnAliases[0]; 255 } 256 } 257 258 259 private String substituteParams(String sqlString) { 260 261 StringBuffer result = new StringBuffer ( sqlString.length() ); 262 int left, right; 263 264 for ( int curr = 0; curr < sqlString.length(); curr = right + 1 ) { 268 if ( ( left = sqlString.indexOf( ParserHelper.HQL_VARIABLE_PREFIX, curr ) ) < 0 ) { 269 result.append( sqlString.substring( curr ) ); 270 break; 271 } 272 273 result.append( sqlString.substring( curr, left ) ); 274 275 right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, left + 1 ); 277 278 boolean foundSeperator = right > 0; 280 int chopLocation = -1; 281 if ( right < 0 ) { 282 chopLocation = sqlString.length(); 283 } 284 else { 285 chopLocation = right; 286 } 287 288 String param = sqlString.substring( left + 1, chopLocation ); 289 addNamedParameter( param ); 290 result.append( "?" ); 291 if ( foundSeperator ) { 292 result.append( sqlString.charAt( right ) ); 293 } 294 else { 295 break; 296 } 297 } 298 return result.toString(); 299 } 300 301 private void addNamedParameter(String name) { 303 Integer loc = new Integer ( parameterCount++ ); 304 Object o = namedParameters.get( name ); 305 if ( o == null ) { 306 namedParameters.put( name, loc ); 307 } 308 else if ( o instanceof Integer ) { 309 ArrayList list = new ArrayList ( 4 ); 310 list.add( o ); 311 list.add( loc ); 312 namedParameters.put( name, list ); 313 } 314 else { 315 ( ( List ) o ).add( loc ); 316 } 317 } 318 319 public Map getNamedParameters() { 320 return namedParameters; 321 } 322 323 public boolean queryHasAliases() { 324 return aliasesFound>0; 325 } 326 327 } 328 | Popular Tags |