1 2 12 package com.versant.core.jdbc.query; 13 14 import com.versant.core.jdo.QueryDetails; 15 import com.versant.core.metadata.*; 16 import com.versant.core.jdo.query.GroupingNode; 17 import com.versant.core.server.CompiledQuery; 18 import com.versant.core.jdbc.FgDs; 19 import com.versant.core.jdbc.JdbcQueryResult; 20 import com.versant.core.jdbc.ProjectionQueryDecoder; 21 import com.versant.core.jdbc.metadata.JdbcColumn; 22 import com.versant.core.jdbc.metadata.JdbcField; 23 import com.versant.core.jdbc.metadata.JdbcRefField; 24 import com.versant.core.jdbc.metadata.JdbcClass; 25 import com.versant.core.jdbc.sql.SqlDriver; 26 import com.versant.core.util.CharBuf; 27 import com.versant.core.common.Debug; 28 29 import java.sql.*; 30 import java.util.HashMap ; 31 import java.util.Map ; 32 import java.util.Set ; 33 import java.util.List ; 34 35 import com.versant.core.common.BindingSupportImpl; 36 37 44 public class JdbcCompiledQuery implements CompiledQuery { 45 46 public static final int PARAM_IN = 0; public static final int PARAM_OUT = 1; 48 public static final int PARAM_OUT_CURSOR = 2; 49 50 private int id; 51 private final QueryDetails qp; 52 53 private Map parCollSqlStrucMap = new HashMap (); 54 55 58 private int classIndex; 59 62 private ClassMetaData[] filterCmds; 63 68 private int[] evictionClassBits; 69 private int[] evictionClassIndexes; 70 73 private boolean cacheble; 74 77 private boolean includeSubclasses; 78 83 private int fetchGroupIndex; 84 87 private boolean randomAccess; 88 91 private int maxRows; 92 96 private int queryResultBatchSize; 97 98 private SqlStruct sqlStruct; 99 100 private boolean parColFetchEnabled; 101 105 private GroupingNode groupByNode; 106 protected int unique; 107 private int selectColumnCount; 108 private boolean copyResultsForCache; 109 public FgDs fgDs; 110 private boolean sqlQuery; 111 private boolean storeProc; 112 private boolean directSql; 113 private MappingInfo mappingInfo; 114 private ClassMetaData cmd; 115 private int[] sqlTypes; 116 119 private int[] paramDirection; 120 private int outParamCount; 121 122 private boolean crossJoinAllowed; 123 private ProjectionQueryDecoder projectionDecoder; 124 125 public JdbcCompiledQuery(ClassMetaData cmd, QueryDetails queryParams) { 126 this.cmd = cmd; 127 if (cmd != null) { 128 this.classIndex = cmd.index; 129 this.includeSubclasses = queryParams.includeSubClasses() && cmd.isInHeirachy(); 130 } else { 131 this.classIndex = -1; 132 } 133 if (queryParams.getLanguage() == QueryDetails.LANGUAGE_SQL) { 134 sqlQuery = true; 135 if (queryParams.getFilter() == null || queryParams.getFilter().trim().length() == 0) { 136 throw BindingSupportImpl.getInstance().invalidOperation( 137 "Must supply a valid filter for a 'SqlQeury'"); 138 } 139 if (queryParams.getFilter().toUpperCase().startsWith("SELECT")) { 140 storeProc = false; 141 directSql = true; 142 } else { 143 storeProc = true; 144 directSql = false; 145 } 146 } 147 148 this.fetchGroupIndex = queryParams.getFetchGroupIndex(); 149 this.randomAccess = queryParams.isRandomAccess(); 150 this.maxRows = queryParams.getMaxResultCount(); 151 this.queryResultBatchSize = queryParams.getResultBatchSize(); 152 if (Debug.DEBUG) { 153 if (queryResultBatchSize <= 0) { 154 throw BindingSupportImpl.getInstance().internal( 155 "The queryDetails.resultBatchSize is not set"); 156 } 157 } 158 this.qp = queryParams; 159 160 if (!sqlQuery) { 161 this.sqlStruct = new SqlStruct(); 162 this.sqlStruct.jdoqlFilter = queryParams.getFilter(); 163 if (sqlStruct.jdoqlFilter == null || sqlStruct.jdoqlFilter.length() == 0) { 164 sqlStruct.jdoqlFilter = "NO FILTER"; 165 } 166 167 parColFetchEnabled = QueryDetails.enableParallelCollectionFetch(qp, 168 cmd.fetchGroups[qp.getFetchGroupIndex()]); 169 } else { 170 unique = QueryDetails.FALSE; 171 String [] types = queryParams.getParamTypes(); 173 int count = queryParams.getParamCount(); 174 sqlTypes = new int[count]; 175 paramDirection = new int[count]; 176 for (int i = 0; i < count; i++) { 177 String type = types[i].toUpperCase(); 178 if (type.startsWith("OUT.")) { 179 outParamCount++; 180 if (type.equals("OUT.CURSOR")) { 181 paramDirection[i] = PARAM_OUT_CURSOR; 183 } else { 184 unique = QueryDetails.TRUE; 186 paramDirection[i] = PARAM_OUT; 188 sqlTypes[i] = getTypeInt(type.substring(type.indexOf(".") + 1)); 189 } 190 } else { 191 sqlTypes[i] = getTypeInt(types[i]); 192 } 193 } 194 } 195 } 196 197 public ClassMetaData getCmd() { 198 return cmd; 199 } 200 201 public void setCmd(ClassMetaData cmd) { 202 this.cmd = cmd; 203 } 204 205 public int getOutParamCount() { 206 return outParamCount; 207 } 208 209 public int[] getSqlTypes() { 210 return sqlTypes; 211 } 212 213 public int[] getParamDirection() { 214 return paramDirection; 215 } 216 217 private int getTypeInt(String val) { 218 try { 219 return Types.class.getDeclaredField(val.toUpperCase()).getInt(null); 220 } catch (Exception e) { 221 throw BindingSupportImpl.getInstance().internal("Param type '" + val 222 + "' is not a valid " + Types.class.getName() + " type."); 223 } 224 } 225 226 public boolean isSqlQuery() { 227 return sqlQuery; 228 } 229 230 public int getSelectColumnCount() { 231 return selectColumnCount; 232 } 233 234 public void setSelectColumnCount(int selectColumnCount) { 235 this.selectColumnCount = selectColumnCount; 236 } 237 238 241 public void process() { 242 if (qp.getUnique() == QueryDetails.TRUE) { 243 unique = QueryDetails.TRUE; 244 } else if (qp.getUnique() == QueryDetails.FALSE) { 245 unique = QueryDetails.FALSE; 246 } else { 247 if (projectionDecoder != null) { 248 if (projectionDecoder.containsAggregate()) { 249 if (groupByNode == null) { 250 if (!projectionDecoder.aggregateOnly()) { 251 unique = QueryDetails.FALSE; 252 } else { 253 unique = QueryDetails.TRUE; 254 } 255 } else { 256 if (projectionDecoder.aggregateOnly()) { 257 unique = QueryDetails.TRUE; 258 } else { 259 unique = QueryDetails.FALSE; 260 } 261 } 262 } else { 263 unique = QueryDetails.FALSE; 264 if (groupByNode != null) { 265 throw BindingSupportImpl.getInstance().invalidOperation("The query contains a 'Group By' " + 266 "expression but no aggregate's."); 267 } 268 } 269 } else { 270 unique = QueryDetails.FALSE; 271 } 272 } 273 274 copyResultsForCache = (projectionDecoder != null 275 && !projectionDecoder.isContainsThisOnly() 276 && projectionDecoder.getRefIndexArray().length > 0); 277 278 sqlStruct.setAggregate( 279 projectionDecoder != null && projectionDecoder.containsAggregate()); 280 281 crossJoinAllowed = (projectionDecoder == null) 282 && parColFetchEnabled 283 && !sqlQuery 284 && !qp.isRandomAccess() 285 && (qp.getMaxResultCount() <= 0); 286 } 287 288 291 public boolean isUnique() { 292 if (unique == QueryDetails.NOT_SET) { 293 throw BindingSupportImpl.getInstance().internal( 294 "The 'unique' value has not been processed."); 295 } 296 if (unique == QueryDetails.TRUE) return true; 297 return false; 298 } 299 300 public boolean isProjectionQuery() { 301 return (projectionDecoder != null); 302 } 303 304 public int getFirstThisIndex() { 305 if (projectionDecoder == null) return -1; 306 return projectionDecoder.getFirstThisIndex(); 307 } 308 309 313 public boolean isContainsThisOnly() { 314 return projectionDecoder.isContainsThisOnly(); 315 } 316 317 321 public boolean isContainsThis() { 322 if (projectionDecoder == null) return false; 323 return projectionDecoder.containsThis(); 324 } 325 326 334 public boolean isCopyResultsForCache() { 335 return copyResultsForCache; 336 } 337 338 341 public boolean isDefaultResult() { 342 if (sqlQuery) { 343 return cmd != null; 344 } 345 if (projectionDecoder == null) return true; 346 return projectionDecoder.isContainsThisOnly(); 347 } 348 349 353 public int[] getRefIndexArray() { 354 if (projectionDecoder == null) { 355 throw BindingSupportImpl.getInstance().internal( 356 "This may only be called on 'projection queries'"); 357 } 358 return projectionDecoder.getRefIndexArray(); 359 } 360 361 public int[] getResultTypeCodes() { 362 return projectionDecoder == null ? null : projectionDecoder.getTypeCodes(); 363 } 364 365 public void setGroupingNode(GroupingNode groupingNode) { 366 groupByNode = groupingNode; 367 } 368 369 public boolean isParColFetchEnabled() { 370 return parColFetchEnabled; 371 } 372 373 public synchronized SqlStruct get(JdbcQueryResult.ColFHKey key) { 374 return (SqlStruct)parCollSqlStrucMap.get(key); 375 } 376 377 public synchronized void add(JdbcQueryResult.ColFHKey key, SqlStruct val) { 378 parCollSqlStrucMap.put(key, val); 379 } 380 381 public SqlStruct getSqlStruct() { 382 return sqlStruct; 383 } 384 385 public int getMaxRows() { 386 return maxRows; 387 } 388 389 public int getQueryResultBatchSize() { 390 return queryResultBatchSize; 391 } 392 393 public ClassMetaData[] getQueryClasses() { 394 return filterCmds; 395 } 396 397 public void setFilterClsIndexs(ClassMetaData[] filterClsIndexs) { 398 this.filterCmds = filterClsIndexs; 399 } 400 401 public int[] getEvictionClassBits() { 402 return evictionClassBits; 403 } 404 405 public int[] getClassIndexes() { 406 return evictionClassIndexes; 407 } 408 409 public QueryDetails getQueryDetails() { 410 return qp; 411 } 412 413 public void setEvictionClassBits(int[] evictionClassBits) { 414 this.evictionClassBits = evictionClassBits; 415 } 416 417 public void setEvictionClassIndexes(int[] evictionClassIndexes) { 418 this.evictionClassIndexes = evictionClassIndexes; 419 } 420 421 public boolean isCacheble() { 422 return cacheble; 423 } 424 425 public void setCacheable(boolean cacheble) { 426 this.cacheble = cacheble; 427 } 428 429 public String getFirstTableOrAlias() { 430 return sqlStruct.getFirstTableOrAlias(); 431 } 432 433 public void setFirstTableOrAlias(String firstTableOrAlias) { 434 sqlStruct.setFirstTableOrAlias(firstTableOrAlias); 435 } 436 437 public boolean isDistinct() { 438 return sqlStruct.isDistinct(); 439 } 440 441 444 public String getSql() { 445 return sqlStruct.getSql(); 446 } 447 448 public int getClassIndex() { 449 return classIndex; 450 } 451 452 public boolean isIncludeSubclasses() { 453 return includeSubclasses; 454 } 455 456 public int getFetchGroupIndex() { 457 return fetchGroupIndex; 458 } 459 460 public FetchGroup getFetchGroup() { 461 return cmd.fetchGroups[fetchGroupIndex]; 462 } 463 464 public boolean isRandomAccess() { 465 return randomAccess; 466 } 467 468 public CharBuf getSqlbuf() { 469 return sqlStruct.getSqlbuf(); 470 } 471 472 public SqlStruct.Param getParamList() { 473 return sqlStruct.getParamList(); 474 } 475 476 481 public void updateSql(SqlDriver driver, Object [] params, boolean forUpdate, 482 boolean forCount) { 483 sqlStruct.updateSql(driver, params, forUpdate, forCount); 484 } 485 486 490 public void setParamsOnPS(ModelMetaData jmd, SqlDriver driver, 491 PreparedStatement ps, Object [] params, String sql) 492 throws SQLException { 493 sqlStruct.setParamsOnPS(jmd, driver, ps, params, sql); 494 } 495 496 public MappingInfo getMappingInfo(ResultSet rs) throws SQLException { 497 if (mappingInfo == null) { 498 mappingInfo = createMappingInfo(rs.getMetaData(), cmd); 499 } 500 return mappingInfo; 501 } 502 503 public boolean equals(Object obj) { 504 if (obj == this) return true; 505 if (obj instanceof JdbcCompiledQuery) { 506 return qp.equals(((JdbcCompiledQuery)obj).qp); 507 } 508 return false; 509 } 510 511 public int hashCode() { 512 return qp.hashCode(); 513 } 514 515 public static MappingInfo createMappingInfo(ResultSetMetaData rsmd, ClassMetaData cmd) throws SQLException { 516 final int count = rsmd.getColumnCount(); 517 MappingInfo mi = new MappingInfo(); 518 mi.colCount = count; 519 if (cmd == null) return mi; 520 mi.cmd = cmd; 521 522 JdbcColumn[] pkCols = ((JdbcClass)cmd.storeClass).table.pk; 523 JdbcColumn discr = ((JdbcClass)cmd.storeClass).classIdCol; 524 525 528 if (discr != null) { 529 for (int i = 1; i <= count; ) { 531 if (discr.name.toUpperCase().equals(rsmd.getColumnName(i).toUpperCase())) { 532 mi.discrIndex = i++; 533 break; 534 } 535 i++; 536 } 537 } 538 539 final boolean appId = cmd.pkFields != null; 540 Set fieldList = new java.util.HashSet (); 541 JdbcField[] jdbcFields = mi.fields = new JdbcField[count]; 542 int[] pkindexes = null; 543 if (appId) { 544 pkindexes = new int[pkCols.length]; 545 } 546 547 for (int i = 1; i <= count;) { 548 String colName = rsmd.getColumnName(i).toUpperCase(); 549 550 if (i == mi.discrIndex) { 552 i++; 553 continue; 554 } 555 556 573 574 if (mi.dsPkIndex == -1 && !appId && pkCols[0].name.toUpperCase().equals(colName)) { 575 mi.dsPkIndex = i; 577 i++; 578 continue; 579 } 580 581 JdbcField field = getSubClassField(colName, cmd, mi.discrIndex != 0); 582 591 if (field != null) { 592 if (fieldList.contains(field)) { 593 System.out.println("Ignoring column '" 595 + colName + "' at index '" 596 + i + "' because this column has already been mapped to '" 597 + field.fmd.classMetaData.qname + "." + field.fmd.name + "'"); 598 i++; 599 continue; 600 } else { 601 if (field.mainTableCols.length == 1) { 602 fieldList.add(field); 603 jdbcFields[i - 1] = field; 604 i++; 605 continue; 606 } else { 607 612 int endIndex = i + field.mainTableCols.length; 613 boolean ok = false; 614 for (int j = i + 1; j < endIndex; j++) { 615 if (((JdbcClass)cmd.storeClass).getColNamesToJdbcField().get(colName) != field) { 616 break; 618 } 619 } 620 621 if (ok) { 622 626 fieldList.add(field); 627 jdbcFields[i - 1] = field; 628 i = endIndex; 629 } else { 630 633 i++; 634 } 635 continue; 636 } 637 } 638 } else { 639 i++; 640 } 642 } 643 644 if (cmd.pkFields != null) { 645 boolean keyFound = false; 647 for (int i = 0; i < cmd.pkFields.length; i++) { 648 FieldMetaData pkField = cmd.pkFields[i]; 649 keyFound = false; 650 for (int j = 0; j < jdbcFields.length; j++) { 651 JdbcField jdbcField = jdbcFields[j]; 652 if (pkField.storeField == jdbcField) { 653 keyFound = true; 654 pkindexes[i] = j; 655 break; 656 } 657 } 658 if (!keyFound) { 660 break; 661 } 662 } 663 664 if (Debug.DEBUG) { 665 if (keyFound) { 666 for (int i = 0; i < cmd.pkFields.length; i++) { 667 FieldMetaData pkField = cmd.pkFields[i]; 668 if (pkField.storeField != jdbcFields[pkindexes[i]]) { 669 throw BindingSupportImpl.getInstance().internal("pk field mismatch"); 670 } 671 } 672 } 673 } 674 if (keyFound) { 675 mi.pkIndexInFieldsArray = pkindexes; 676 } 677 } 678 return mi; 683 } 684 685 688 private static JdbcField getRefField(String colName, ClassMetaData cmd, boolean includeSubs, 689 RefFieldMapping refFieldMapping) { 690 if (!includeSubs) { 691 return getRefFieldImp(cmd, colName, true); 692 } else { 693 List cmds = cmd.getHeirarchyList(); 694 for (int i = 0; i < cmds.size(); i++) { 695 JdbcField jdbcField = getRefFieldImp((ClassMetaData) cmds.get(i), colName, true); 696 if (jdbcField != null) return jdbcField; 697 } 698 } 699 return null; 700 } 701 702 705 private static JdbcField getRefFieldImp(ClassMetaData cmd, String colName, boolean includeSubs) { 706 FieldMetaData[] fields = cmd.stateFields; 707 for (int i = 0; i < fields.length; i++) { 708 FieldMetaData fmd = fields[i]; 709 if (fmd.category == MDStatics.CATEGORY_REF) { 710 JdbcField jdbcField = getSubClassField(colName, fmd.typeMetaData, includeSubs); 711 if (jdbcField != null) return jdbcField; 712 } 713 } 714 return null; 715 } 716 717 720 private static JdbcField getSubClassField(String colName, ClassMetaData cmd, boolean checkSubClasses) { 721 if (!checkSubClasses) { 722 return (JdbcField)((JdbcClass)cmd.storeClass).getColNamesToJdbcField().get(colName); 723 } else { 724 List subsList = cmd.getHeirarchyList(); 725 for (int i = 0; i < subsList.size(); i++) { 726 ClassMetaData icmd = (ClassMetaData) subsList.get(i); 727 JdbcField field = 728 (JdbcField)((JdbcClass)icmd.storeClass).getColNamesToJdbcField().get(colName); 729 if (field != null) return field; 730 } 731 } 732 return null; 733 } 734 735 public boolean isStoredProc() { 736 return storeProc; 737 } 738 739 public boolean isDirectSql() { 740 return directSql; 741 } 742 743 public boolean isCrossJoinAllowed() { 744 return crossJoinAllowed; 745 } 746 747 public ProjectionQueryDecoder getProjectionDecoder() { 748 return projectionDecoder; 749 } 750 751 public void setProjectionDecoder(ProjectionQueryDecoder decoder) { 752 this.projectionDecoder = decoder; 753 } 754 755 758 public boolean isEJBQLHack() { 759 return false; 760 } 761 762 763 764 768 public static class RefFieldMapping { 769 public JdbcRefField fromField; 770 public JdbcField toField; 771 772 public void clear() { 773 fromField = null; 774 toField = null; 775 } 776 } 777 778 782 public static class MappingInfo { 783 public ClassMetaData cmd; 784 787 public int dsPkIndex = -1; 788 791 public int discrIndex = 0; 792 796 public JdbcField[] fields; 797 public int colCount; 798 public boolean pkFieldsFound; 799 public boolean discriminatorColFound; 800 public int[] pkIndexInFieldsArray; 801 802 public void dump() { 803 System.out.println("MappingInfo.dump@" + System.identityHashCode(this)); 804 for (int i = 0; i < fields.length; i++) { 805 JdbcField jdbcField = fields[i]; 806 if (jdbcField != null) { 807 System.out.println("jdbcField = " + jdbcField); 808 } 809 } 810 } 811 812 815 public boolean isPkValid() { 816 return dsPkIndex != -1 || pkIndexInFieldsArray != null; 817 } 818 } 819 820 public String toString() { 821 return sqlStruct == null ? "sqlStruct is null" : sqlStruct.getSql(); 822 } 823 824 public int getId() { 825 return id; 826 } 827 828 public void setId(int id) { 829 this.id = id; 830 } 831 832 } 833 | Popular Tags |