| 1 package org.apache.ojb.broker.accesslayer.sql; 2 3 17 18 import java.util.ArrayList ; 19 import java.util.Collection ; 20 import java.util.Enumeration ; 21 import java.util.HashMap ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import org.apache.ojb.broker.PersistenceBrokerSQLException; 27 import org.apache.ojb.broker.accesslayer.JoinSyntaxTypes; 28 import org.apache.ojb.broker.metadata.ClassDescriptor; 29 import org.apache.ojb.broker.metadata.CollectionDescriptor; 30 import org.apache.ojb.broker.metadata.DescriptorRepository; 31 import org.apache.ojb.broker.metadata.FieldDescriptor; 32 import org.apache.ojb.broker.metadata.FieldHelper; 33 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; 34 import org.apache.ojb.broker.metadata.SuperReferenceDescriptor; 35 import org.apache.ojb.broker.platforms.Platform; 36 import org.apache.ojb.broker.query.BetweenCriteria; 37 import org.apache.ojb.broker.query.Criteria; 38 import org.apache.ojb.broker.query.ExistsCriteria; 39 import org.apache.ojb.broker.query.FieldCriteria; 40 import org.apache.ojb.broker.query.InCriteria; 41 import org.apache.ojb.broker.query.LikeCriteria; 42 import org.apache.ojb.broker.query.MtoNQuery; 43 import org.apache.ojb.broker.query.NullCriteria; 44 import org.apache.ojb.broker.query.Query; 45 import org.apache.ojb.broker.query.QueryByCriteria; 46 import org.apache.ojb.broker.query.QueryBySQL; 47 import org.apache.ojb.broker.query.SelectionCriteria; 48 import org.apache.ojb.broker.query.SqlCriteria; 49 import org.apache.ojb.broker.query.UserAlias; 50 import org.apache.ojb.broker.util.SqlHelper; 51 import org.apache.ojb.broker.util.SqlHelper.PathInfo; 52 import org.apache.ojb.broker.util.logging.Logger; 53 import org.apache.ojb.broker.util.logging.LoggerFactory; 54 55 61 public abstract class SqlQueryStatement implements SqlStatement, JoinSyntaxTypes 62 { 63 private static final String ALIAS_SEPARATOR = "."; 64 private static final String M_N_ALIAS = "M_N"; 65 private String sql; 66 67 private SqlQueryStatement m_parentStatement; 68 69 private Logger m_logger; 70 71 private TableAlias m_root; 72 73 private TableAlias m_search; 74 75 private QueryByCriteria m_query; 76 77 private HashMap m_pathToAlias = new HashMap (); 78 79 private HashMap m_cldToAlias = new HashMap (); 80 81 private HashMap m_joinTreeToCriteria = new HashMap (); 82 83 private Platform m_platform; 84 private ClassDescriptor m_baseCld; 85 private ClassDescriptor m_searchCld; 86 87 private int m_aliasCount = 0; 88 protected HashMap m_attrToFld = new HashMap (); 90 98 public SqlQueryStatement(Platform pf, ClassDescriptor cld, Query query, Logger logger) 99 { 100 this(null, pf, cld, query, logger); 101 } 102 103 112 public SqlQueryStatement(SqlQueryStatement parent, Platform pf, ClassDescriptor cld, Query query, Logger logger) 113 { 114 m_logger = logger != null ? logger : LoggerFactory.getLogger(SqlQueryStatement.class); 115 m_parentStatement = parent; 116 m_query = (QueryByCriteria) query; 117 m_platform = pf; 118 m_searchCld = cld; 119 120 if ((m_query == null) || (m_query.getBaseClass() == m_query.getSearchClass())) 121 { 122 m_baseCld = m_searchCld; 123 } 124 else 125 { 126 m_baseCld = cld.getRepository().getDescriptorFor(query.getBaseClass()); 127 } 128 129 m_root = createTableAlias(m_baseCld, null, ""); 130 131 if (m_query instanceof MtoNQuery) 133 { 134 MtoNQuery mnQuery = (MtoNQuery)m_query; 135 TableAlias mnAlias = new TableAlias(mnQuery.getIndirectionTable(), M_N_ALIAS); 136 setTableAliasForPath(mnQuery.getIndirectionTable(), null, mnAlias); 137 } 138 139 if (m_searchCld == m_baseCld) 140 { 141 m_search = m_root; 142 } 143 else 144 { 145 m_search = getTableAlias(m_query.getObjectProjectionAttribute(), false, null, null, m_query.getPathClasses()); 146 } 147 148 buildSuperJoinTree(m_root, m_baseCld, "" ,false); 150 151 buildMultiJoinTree(m_root, m_baseCld, "", true); 152 153 if (query != null) 157 { 158 splitCriteria(); 159 } 160 } 161 162 protected ClassDescriptor getBaseClassDescriptor() 163 { 164 return m_baseCld; 165 } 166 167 protected ClassDescriptor getSearchClassDescriptor() 168 { 169 return m_searchCld; 170 } 171 172 183 protected AttributeInfo getAttributeInfo(String attr, boolean useOuterJoins, UserAlias aUserAlias, Map pathClasses) 184 { 185 AttributeInfo result = new AttributeInfo(); 186 TableAlias tableAlias; 187 SqlHelper.PathInfo pathInfo = SqlHelper.splitPath(attr); 188 String colName = pathInfo.column; 189 int sp; 190 191 if (colName.startsWith(Criteria.PARENT_QUERY_PREFIX) && m_parentStatement != null) 195 { 196 String [] fieldNameRef = {colName.substring(Criteria.PARENT_QUERY_PREFIX.length())}; 197 return m_parentStatement.getAttributeInfo(fieldNameRef[0], useOuterJoins, aUserAlias, pathClasses); 198 } 199 200 sp = colName.lastIndexOf("."); 201 if (sp == -1) 202 { 203 tableAlias = getRoot(); 204 } 205 else 206 { 207 String pathName = colName.substring(0, sp); 208 String [] fieldNameRef = {colName.substring(sp + 1)}; 209 210 tableAlias = getTableAlias(pathName, useOuterJoins, aUserAlias, fieldNameRef, pathClasses); 211 218 if ((tableAlias == null) && (colName.lastIndexOf(".") == -1)) 219 { 220 223 tableAlias = getTableAlias(pathName, useOuterJoins, new UserAlias(pathName, pathName, pathName), null, pathClasses); 224 } 225 226 if (tableAlias != null) 227 { 228 pathInfo.column = fieldNameRef[0]; 231 } 232 } 233 234 result.tableAlias = tableAlias; 235 result.pathInfo = pathInfo; 236 return result; 237 } 238 239 245 protected String getColName(TableAlias aTableAlias, PathInfo aPathInfo, boolean translate) 246 { 247 String result = null; 248 249 if (!translate) 251 { 252 return aPathInfo.column; 253 } 254 255 if (aTableAlias.cld == null && M_N_ALIAS.equals(aTableAlias.alias)) 257 { 258 return getIndirectionTableColName(aTableAlias, aPathInfo.path); 259 } 260 261 FieldDescriptor fld = getFieldDescriptor(aTableAlias, aPathInfo); 263 264 if (fld != null) 265 { 266 m_attrToFld.put(aPathInfo.path, fld); 267 268 if (!fld.getClassDescriptor().getFullTableName().equals(aTableAlias.table) && aTableAlias.hasJoins()) 270 { 271 Iterator itr = aTableAlias.joins.iterator(); 272 while (itr.hasNext()) 273 { 274 Join join = (Join) itr.next(); 275 if (join.right.table.equals(fld.getClassDescriptor().getFullTableName())) 276 { 277 result = join.right.alias + "." + fld.getColumnName(); 278 break; 279 } 280 } 281 282 if (result == null) 283 { 284 result = aPathInfo.column; 285 } 286 } 287 else 288 { 289 result = aTableAlias.alias + "." + fld.getColumnName(); 290 } 291 } 292 else if ("*".equals(aPathInfo.column)) 293 { 294 result = aPathInfo.column; 295 } 296 else 297 { 298 result = aPathInfo.column; 300 } 301 302 return result; 303 } 304 305 314 protected boolean appendColName(TableAlias aTableAlias, PathInfo aPathInfo, boolean translate, StringBuffer buf) 315 { 316 String prefix = aPathInfo.prefix; 317 String suffix = aPathInfo.suffix; 318 String colName = getColName(aTableAlias, aPathInfo, translate); 319 320 if (prefix != null) { 322 buf.append(prefix); 323 } 324 325 buf.append(colName); 326 327 if (suffix != null) { 329 buf.append(suffix); 330 } 331 332 return true; 333 } 334 335 342 protected FieldDescriptor getFieldDescriptor(TableAlias aTableAlias, PathInfo aPathInfo) 343 { 344 FieldDescriptor fld = null; 345 String colName = aPathInfo.column; 346 347 if (aTableAlias != null) 348 { 349 fld = aTableAlias.cld.getFieldDescriptorByName(colName); 350 if (fld == null) 351 { 352 ObjectReferenceDescriptor ord = aTableAlias.cld.getObjectReferenceDescriptorByName(colName); 353 if (ord != null) 354 { 355 fld = getFldFromReference(aTableAlias, ord); 356 } 357 else 358 { 359 fld = getFldFromJoin(aTableAlias, colName); 360 } 361 } 362 } 363 364 return fld; 365 } 366 367 370 private FieldDescriptor getFldFromJoin(TableAlias aTableAlias, String aColName) 371 { 372 FieldDescriptor fld = null; 373 374 if (aTableAlias.joins != null) 376 { 377 Iterator itr = aTableAlias.joins.iterator(); 378 while (itr.hasNext()) 379 { 380 Join join = (Join) itr.next(); 381 ClassDescriptor cld = join.right.cld; 382 383 if (cld != null) 384 { 385 fld = cld.getFieldDescriptorByName(aColName); 386 if (fld != null) 387 { 388 break; 389 } 390 391 } 392 } 393 } 394 return fld; 395 } 396 397 400 private FieldDescriptor getFldFromReference(TableAlias aTableAlias, ObjectReferenceDescriptor anOrd) 401 { 402 FieldDescriptor fld = null; 403 404 if (aTableAlias == getRoot()) 405 { 406 FieldDescriptor[] fk = anOrd.getForeignKeyFieldDescriptors(aTableAlias.cld); 408 if (fk.length > 0) 409 { 410 fld = fk[0]; 411 } 412 } 413 else 414 { 415 422 ClassDescriptor cld = aTableAlias.cld.getRepository().getDescriptorFor(anOrd.getItemClass()); 423 if (cld != null) 424 { 425 fld = aTableAlias.cld.getFieldDescriptorByName(cld.getPkFields()[0].getPersistentField().getName()); 426 } 427 } 428 429 return fld; 430 } 431 432 440 protected boolean appendColName(String attr, boolean useOuterJoins, UserAlias aUserAlias, StringBuffer buf) 441 { 442 AttributeInfo attrInfo = getAttributeInfo(attr, useOuterJoins, aUserAlias, getQuery().getPathClasses()); 443 TableAlias tableAlias = attrInfo.tableAlias; 444 445 return appendColName(tableAlias, attrInfo.pathInfo, (tableAlias != null), buf); 446 } 447 448 456 protected boolean appendColName(String attr, String attrAlias, boolean useOuterJoins, UserAlias aUserAlias, 457 StringBuffer buf) 458 { 459 AttributeInfo attrInfo = getAttributeInfo(attr, useOuterJoins, aUserAlias, getQuery().getPathClasses()); 460 TableAlias tableAlias = attrInfo.tableAlias; 461 PathInfo pi = attrInfo.pathInfo; 462 463 if (pi.suffix != null) 464 { 465 pi.suffix = pi.suffix + " as " + attrAlias; 466 } 467 else 468 { 469 pi.suffix = " as " + attrAlias; 470 } 471 472 return appendColName(tableAlias, pi, true, buf); 473 } 474 475 480 protected void ensureColumns(List columns, List existingColumns) 481 { 482 if (columns == null || columns.isEmpty()) 483 { 484 return; 485 } 486 487 Iterator iter = columns.iterator(); 488 489 while (iter.hasNext()) 490 { 491 FieldHelper cf = (FieldHelper) iter.next(); 492 if (!existingColumns.contains(cf.name)) 493 { 494 getAttributeInfo(cf.name, false, null, getQuery().getPathClasses()); 495 } 496 } 497 } 498 499 508 protected List ensureColumns(List columns, List existingColumns, StringBuffer buf) 509 { 510 if (columns == null || columns.isEmpty()) 511 { 512 return existingColumns; 513 } 514 515 Iterator iter = columns.iterator(); 516 int ojb_col = existingColumns.size() + 1; 517 518 while (iter.hasNext()) 519 { 520 FieldHelper cf = (FieldHelper) iter.next(); 521 if (!existingColumns.contains(cf.name)) 522 { 523 existingColumns.add(cf.name); 524 525 buf.append(","); 526 appendColName(cf.name, "ojb_col_" + ojb_col, false, null, buf); 527 ojb_col++; 528 } 529 } 530 531 return existingColumns; 532 } 533 534 535 541 protected void appendWhereClause(StringBuffer where, Criteria crit, StringBuffer stmt) 542 { 543 if (where.length() == 0) 544 { 545 where = null; 546 } 547 548 if (where != null || (crit != null && !crit.isEmpty())) 549 { 550 stmt.append(" WHERE "); 551 appendClause(where, crit, stmt); 552 } 553 } 554 555 561 protected void appendHavingClause(StringBuffer having, Criteria crit, StringBuffer stmt) 562 { 563 if (having.length() == 0) 564 { 565 having = null; 566 } 567 568 if (having != null || crit != null) 569 { 570 stmt.append(" HAVING "); 571 appendClause(having, crit, stmt); 572 } 573 } 574 575 581 protected void appendClause(StringBuffer clause, Criteria crit, StringBuffer stmt) 582 { 583 590 591 if (clause != null) 592 { 593 stmt.append(clause.toString()); 594 } 595 if (crit != null) 596 { 597 if (clause == null) 598 { 599 stmt.append(asSQLStatement(crit)); 600 } 601 else 602 { 603 stmt.append(" AND ("); 604 stmt.append(asSQLStatement(crit)); 605 stmt.append(")"); 606 } 607 608 } 609 } 610 611 614 private String asSQLStatement(Criteria crit) 615 { 616 Enumeration e = crit.getElements(); 617 StringBuffer statement = new StringBuffer (); 618 619 while (e.hasMoreElements()) 620 { 621 Object o = e.nextElement(); 622 if (o instanceof Criteria) 623 { 624 Criteria pc = (Criteria) o; 625 626 if (pc.isEmpty()) 627 { 628 continue; } 630 631 String addAtStart = ""; 632 String addAtEnd = ""; 633 634 if (pc.isEmbraced()) 636 { 637 addAtStart = " ("; 638 addAtEnd = ")"; 639 } 640 641 switch (pc.getType()) 642 { 643 case (Criteria.OR) : 644 { 645 if (statement.length() > 0) 646 { 647 statement.append(" OR "); 648 } 649 statement.append(addAtStart); 650 statement.append(asSQLStatement(pc)); 651 statement.append(addAtEnd); 652 break; 653 } 654 case (Criteria.AND) : 655 { 656 if (statement.length() > 0) 657 { 658 statement.insert(0, "( "); 659 statement.append(") AND "); 660 } 661 statement.append(addAtStart); 662 statement.append(asSQLStatement(pc)); 663 statement.append(addAtEnd); 664 break; 665 } 666 } 667 } 668 else 669 { 670 SelectionCriteria c = (SelectionCriteria) o; 671 if (statement.length() > 0) 672 { 673 statement.insert(0, "("); 674 statement.append(") AND "); 675 } 676 appendSQLClause(c, statement); 677 } 678 } 680 if (crit.isNegative()) 682 { 683 statement.insert(0, " NOT ("); 684 statement.append(")"); 685 } 686 687 return (statement.length() == 0 ? null : statement.toString()); 688 } 689 690 698 private void appendBetweenCriteria(TableAlias alias, PathInfo pathInfo, BetweenCriteria c, StringBuffer buf) 699 { 700 appendColName(alias, pathInfo, c.isTranslateAttribute(), buf); 701 buf.append(c.getClause()); 702 appendParameter(c.getValue(), buf); 703 buf.append(" AND "); 704 appendParameter(c.getValue2(), buf); 705 } 706 707 711 private void appendExistsCriteria(ExistsCriteria c, StringBuffer buf) 712 { 713 Query subQuery = (Query) c.getValue(); 714 715 buf.append(c.getClause()); 716 appendSubQuery(subQuery, buf); 717 } 718 719 728 private void appendFieldCriteria(TableAlias alias, PathInfo pathInfo, FieldCriteria c, StringBuffer buf) 729 { 730 appendColName(alias, pathInfo, c.isTranslateAttribute(), buf); 731 buf.append(c.getClause()); 732 733 if (c.isTranslateField()) 734 { 735 appendColName((String ) c.getValue(), false, c.getUserAlias(), buf); 736 } 737 else 738 { 739 buf.append(c.getValue()); 740 } 741 } 742 743 748 private String getIndirectionTableColName(TableAlias mnAlias, String path) 749 { 750 int dotIdx = path.lastIndexOf("."); 751 String column = path.substring(dotIdx); 752 return mnAlias.alias + column; 753 } 754 755 763 private void appendInCriteria(TableAlias alias, PathInfo pathInfo, InCriteria c, StringBuffer buf) 764 { 765 appendColName(alias, pathInfo, c.isTranslateAttribute(), buf); 766 buf.append(c.getClause()); 767 768 if (c.getValue() instanceof Collection ) 769 { 770 Object [] values = ((Collection ) c.getValue()).toArray(); 771 int size = ((Collection ) c.getValue()).size(); 772 773 buf.append("("); 774 if (size > 0) 775 { 776 for (int i = 0; i < size - 1; i++) 777 { 778 appendParameter(values[i], buf); 779 buf.append(","); 780 } 781 appendParameter(values[size - 1], buf); 782 } 783 buf.append(")"); 784 } 785 else 786 { 787 appendParameter(c.getValue(), buf); 788 } 789 } 790 791 799 private void appendNullCriteria(TableAlias alias, PathInfo pathInfo, NullCriteria c, StringBuffer buf) 800 { 801 appendColName(alias, pathInfo, c.isTranslateAttribute(), buf); 802 buf.append(c.getClause()); 803 } 804 805 809 private void appendSQLCriteria(SqlCriteria c, StringBuffer buf) 810 { 811 buf.append(c.getClause()); 812 } 813 814 820 private void appendSelectionCriteria(TableAlias alias, PathInfo pathInfo, SelectionCriteria c, StringBuffer buf) 821 { 822 appendColName(alias, pathInfo, c.isTranslateAttribute(), buf); 823 buf.append(c.getClause()); 824 appendParameter(c.getValue(), buf); 825 } 826 827 833 private void appendLikeCriteria(TableAlias alias, PathInfo pathInfo, LikeCriteria c, StringBuffer
|