Project

General

Profile

Dropped_redundant_ORDER-BY_elements.patch

proposed update #1 - Ovidiu Maxiniuc, 10/01/2020 10:34 AM

Download (33.5 KB)

View differences:

src/com/goldencode/p2j/persist/AdaptiveQuery.java 2020-10-01 13:56:04 +0000
4 4
**
5 5
** Copyright (c) 2004-2019, Golden Code Development Corporation.
6 6
**
7
** -#- -I- --Date-- --JPRM-- ----------------------------Description-----------------------------
7
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
8 8
** 001 ECF 20060721   @28133 Created initial version. Query which adapts
9 9
**                           its retrieval type from preselect to dynamic,
10 10
**                           based upon DMO state change notifications.
......
308 308
** 112 SVL 20191218          Handled case when REPOSITION TO ROWID fails.
309 309
** 113 ECF 20200215          New ORM implementation.
310 310
** 114 CA  20200924          Replaced DMO property access from reflection to property's data handler.
311
**     OM  20201001          Dropped redundant ORDER BY elements in multi-table queries.
311 312
*/
312 313

  
313 314
/*
......
3151 3152
   }
3152 3153
   
3153 3154
   /**
3154
    * Assemble the <code>order by</code> clause for an HQL query by combining
3155
    * the sort criteria from each query component sequentially.  Uses the
3156
    * form:
3157
    * <pre>
3158
    *   order by {{dmo.property} {asc/desc}} [, ...]
3159
    * </pre>
3160
    * <p>
3161
    * Any text-based sort criteria are augmented with the necessary upper()
3162
    * and rtrim() functions.
3163
    *
3164
    * @param   buf
3165
    *          String buffer into which clause is assembled.
3166
    *
3167
    * @return  List of <code>SortCriterion</code> objects which describe the
3168
    *          sort behavior for this query.
3155
    * Assemble the {@code order by} clause for an HQL query by combining the sort criteria from each query
3156
    * component sequentially.
3157
    * Any text-based sort criteria are augmented with the necessary upper() and rtrim() functions.
3158
    *
3159
    * @return  List of {@code SortCriterion} objects which describe the sort behavior for this query.
3169 3160
    *
3170 3161
    * @throws  PersistenceException
3171
    *          if the sort clause of any query component contains any
3172
    *          unqualified property names;  if a sort clause contains a
3173
    *          reference to an unrecognized record buffer.
3162
    *          if the sort clause of any query component contains any unqualified property names;  if a sort
3163
    *          clause contains a reference to an unrecognized record buffer.
3174 3164
    * 
3175 3165
    * @throws  PersistenceException
3176
    *          if there is an error creating the <code>HQLPreprocessor</code>
3177
    *          from which setup data is required.
3166
    *          if there is an error creating the {@code HQLPreprocessor} from which setup data is required.
3178 3167
    */
3179
   protected List<SortCriterion> assembleOrderByClause(StringBuilder buf)
3168
   @Override
3169
   protected List<SortCriterion> assembleOrderByClause()
3180 3170
   throws PersistenceException
3181 3171
   {
3182 3172
      List<SortCriterion> all = new ArrayList<>();
......
3202 3192
         List<SortCriterion> sortCriteria = next.getSortCriteria();
3203 3193
         all.addAll(sortCriteria);
3204 3194
         
3205
         if (i == 0)
3206
         {
3207
            buf.append("order by ");
3208
         }
3209
         else
3210
         {
3211
            buf.append(", ");
3212
         }
3213
         
3214
         assembleOrderByClauseNoPreamble(buf, sortCriteria);
3195
         assembleOrderByClause(sortCriteria);
3215 3196
      }
3216 3197
      
3217 3198
      return all;
src/com/goldencode/p2j/persist/HQLPreprocessor.java 2020-10-01 14:01:33 +0000
4 4
**
5 5
** Copyright (c) 2004-2020, Golden Code Development Corporation.
6 6
**
7
** -#- -I- --Date-- --JPRM-- -----------------------------Description-----------------------------
7
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
8 8
** 001 ECF 20060317   @25230 Created initial version. Identifies certain
9 9
**                           patterns in a where clause string, which
10 10
**                           indicate unsupported HQL "shortcut" syntax,
......
247 247
** 086 CA  20191009          Added where and sort clause translation in case of bound buffers.
248 248
** 087 ECF 20200906          New ORM implementation.
249 249
** 088 AIL 20200831          Skipped parenthesis inside simplifyUnknowns.
250
** 089 OM  20201001          Dropped redundant ORDER BY elements in multi-table queries.
250 251
*/
251 252

  
252 253
/*
......
307 308
import java.io.*;
308 309
import java.lang.reflect.*;
309 310
import java.util.*;
311
import java.util.List;
310 312
import java.util.function.*;
311 313
import java.util.logging.*;
314
import antlr.collections.*;
312 315
import com.goldencode.ast.*;
313 316
import com.goldencode.util.*;
314 317
import com.goldencode.p2j.persist.dialect.*;
......
605 608
   private Map<String, RecordBuffer> bufferMap = null;
606 609
   
607 610
   /**
611
    * The substitution pairs. They are optionally computed in {@code preprocess} if {@code replacementAliases}
612
    * are present.*/
613
   private List<PropertyPair> substPairs = null;
614
   
615
   /**
608 616
    * Factory method which accepts an unprocessed where clause, the database
609 617
    * instance and the database dialect associated with the enclosing query,
610 618
    * the DMO implementation class, and the substitution parameters, if any,
......
1124 1132
   }
1125 1133
   
1126 1134
   /**
1135
    * Obtain the substitution pair list, if any.
1136
    * 
1137
    * @return  the substitution pair list or {@code null} if none was detected.
1138
    */
1139
   public List<PropertyPair> getSubstPairs()
1140
   {
1141
      return substPairs;
1142
   }
1143
   
1144
   /**
1127 1145
    * Check if the preprocessed query is a simple RECID/ROWID lookup query.
1128 1146
    * <p>
1129 1147
    * Generally, we can easily find such records using persistent database or dirty database for
......
1388 1406
      {
1389 1407
         if (referenceSubs != null)
1390 1408
         {
1391
            inlineReferenceSubs(root, referenceSubs);
1409
            substPairs = inlineReferenceSubs(root, referenceSubs);
1392 1410
         }
1393 1411
         
1394 1412
         // Annotate query substitution parameter nodes with their data types.
......
1941 1959
   }
1942 1960
   
1943 1961
   /**
1944
    * Given an array containing one or more strings and zero or more nulls, replace those query
1945
    * substitution parameters in the where clause AST which positionally coincide with the
1946
    * non-null strings in the array. Each non-null string in the array represents a field
1947
    * reference to a specific DMO property. The SUBST AST node whose index coincides with that of
1948
    * a field reference in the array is replaced with a an ALIAS node which has a PROPERTY child.
1949
    * If the field reference represents an extent field element, the PROPERTY node has an
1950
    * LBRACKET child and an INDEX grandchild.
1962
    * Given an array containing one or more strings and zero or more nulls, replace those query substitution
1963
    * parameters in the where clause AST which positionally coincide with the non-null strings in the array.
1964
    * Each non-null string in the array represents a field reference to a specific DMO property. The SUBST
1965
    * AST node whose index coincides with that of a field reference in the array is replaced with a an ALIAS
1966
    * node which has a PROPERTY child. If the field reference represents an extent field element, the PROPERTY
1967
    * node has an LBRACKET child and an INDEX grandchild.
1951 1968
    * 
1952 1969
    * @param   root
1953 1970
    *          HQL AST root node.
1954 1971
    * @param   referenceSubs
1955 1972
    *          Array of field references and nulls.
1973
    *
1974
    * @return  A list of pairs of properties (belonging to different tables) whose equality is guaranteed by
1975
    *          the where predicate. These will be used to simplify the sort order when the SQL query is
1976
    *          composed.
1956 1977
    */
1957
   private void inlineReferenceSubs(HQLAst root, String[] referenceSubs)
1978
   private List<PropertyPair> inlineReferenceSubs(HQLAst root, String[] referenceSubs)
1958 1979
   {
1959 1980
      int len = referenceSubs.length;
1960
      
1961 1981
      Map<HQLAst, String> replacements = new HashMap<>();
1962 1982
      
1963 1983
      Iterator<Aast> iter = root.iterator();
......
1988 2008
         }
1989 2009
      }
1990 2010
      
2011
      if (replacements.isEmpty())
2012
      {
2013
         return null;
2014
      }
2015
      
2016
      List<PropertyPair> ret = new ArrayList<>(replacements.size());
1991 2017
      for (Map.Entry<HQLAst, String> next : replacements.entrySet())
1992 2018
      {
1993 2019
         HQLAst aliasAst = next.getKey();
......
2025 2051
         }
2026 2052
         
2027 2053
         // re-parent ALIAS with upper function if needed
2054
         HQLAst parent = (HQLAst) aliasAst.getParent();
2028 2055
         if (upper)
2029 2056
         {
2030
            HQLAst parent = (HQLAst) aliasAst.getParent();
2031 2057
            int idxPos = aliasAst.getIndexPos();
2032 2058
            
2033 2059
            HQLAst upperAst = createAstNode(FUNCTION, "upper", null);
......
2035 2061
            aliasAst.remove();
2036 2062
            parent.graftAt(upperAst, idxPos);
2037 2063
            upperAst.graft(aliasAst);
2064
            aliasAst = upperAst; 
2065
         }
2066
         
2067
         if (parent == null)
2068
         {
2069
            return null;
2070
         }
2071
         
2072
         // check if all the parent's are AND (and parenthesis) nodes
2073
         Aast it = parent.getParent();
2074
         while (it != null)
2075
         {
2076
            if (it.getType() == AND || it.getType() == LPARENS)
2077
            {
2078
               it = it.getParent();
2079
            }
2080
            else
2081
            {
2082
               break;
2083
            }
2084
         }
2085
         
2086
         // if [it] isn't null then it represents the node different from AND and LPARENS in the parent's path
2087
         if (it == null)
2088
         {
2089
            // analyze the left side of the operator
2090
            AST refNode = parent.getFirstChild();
2091
            if (refNode == aliasAst)
2092
            {
2093
               // handle [A op B] and [B op A] cases
2094
               refNode = refNode.getNextSibling();
2095
            }
2096
            while (refNode.getType() == FUNCTION && 
2097
                   (refNode.getText().equals("upper") || refNode.getText().equals("rtrim")))
2098
            {
2099
               refNode = refNode.getFirstChild();
2100
            }
2101
            // TODO: need to check whether refNode.type == ALIAS and refNode.firstChild.type == PROPERTY ? 
2102
            
2103
            ret.add(new PropertyPair(
2104
                  refNode.getText(), refNode.getFirstChild().getText(), alias, property, parent.getText()));
2038 2105
         }
2039 2106
      }
2107
      
2108
      return ret;
2040 2109
   }
2041 2110
   
2042 2111
   /**
......
5985 6054
         result = 37 * result + dropAlias.hashCode();
5986 6055
         result = 37 * result + replacementAlias.hashCode();
5987 6056
         result = 37 * result + (informational ? 0 : 1);
5988
      
6057
         
5989 6058
         return result;
5990 6059
      }
5991 6060
   }
6061
   
6062
   /** A public container for storing a pair of properties. It is immutable, used for transfering data. */
6063
   public static final class PropertyPair
6064
   {
6065
      /** Operator used for joining the properties. */
6066
      private final String operator;
6067
      
6068
      /** The full name of the first (left) property. */
6069
      private final String name1;
6070
      
6071
      /** The full name of the second (right) property. */
6072
      private final String name2;
6073
      
6074
      /**
6075
       *  The constructor initializes all the fields.
6076
       * 
6077
       * @param   alias1
6078
       *          The alias (table) of the first (left) property.
6079
       * @param   property1
6080
       *          The name of the property from first (left) table.
6081
       * @param   alias2
6082
       *          The alias (table) of the second (right) property.
6083
       * @param   property2
6084
       *          The name of the property from second (right) table.
6085
       * @param   operator
6086
       *          The operator which creates a relations between the two fields. We are interested only in
6087
       *          "=" operator, but this leave room for other usages of this class.
6088
       */
6089
      public PropertyPair(String alias1, String property1, String alias2, String property2, String operator)
6090
      {
6091
         this.operator = operator;
6092
         this.name1 = alias1 + "." + property1;
6093
         this.name2 = alias2 + "." + property2;
6094
      }
6095
      
6096
      /**
6097
       * Obtain the full name of the first (left) property.
6098
       *
6099
       * @return  the full name of the first (left) property.
6100
       */
6101
      public String getLeft()
6102
      {
6103
         return name1;
6104
      }
6105
      
6106
      /**
6107
       * Obtain the full name of the second (right) property.
6108
       *
6109
       * @return  the full name of the second (right) property.
6110
       */
6111
      public String getRight()
6112
      {
6113
         return name2;
6114
      }
6115
      
6116
      /**
6117
       * Obtain the operator used for joining the properties..
6118
       *
6119
       * @return the operator used for joining the properties.
6120
       */
6121
      public String getOperator()
6122
      {
6123
         return operator;
6124
      }
6125
   }
5992 6126
}
src/com/goldencode/p2j/persist/PreselectQuery.java 2020-10-01 14:15:33 +0000
4 4
**
5 5
** Copyright (c) 2004-2020, Golden Code Development Corporation.
6 6
**
7
** -#- -I- --Date-- --JPRM-- --------------------------Description-------------------------------
7
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
8 8
** 001 ECF 20051115   @23396 Created initial version, based on prototype
9 9
**                           CursoredQuery. Backing support for queries
10 10
**                           which must support the Progress, row-level
......
560 560
** 176 AIL 20200908          Reset offSet flag when adding new row through createResultListEntry.
561 561
**     AIL 20200910          Restrict resetting offSet flag only for browsed queries.
562 562
**     ECF 20200919          Persistence.load API signature change.
563
**     OM  20201001          Dropped redundant ORDER BY elements in multi-table queries.
563 564
*/
564 565

  
565 566
/*
......
4409 4410
   }
4410 4411
   
4411 4412
   /**
4412
    * Assemble the from clause for an HQL query. The class name of each
4413
    * DMO is decapitalized to produce an alias for that object. Form of
4414
    * the clause is:
4413
    * Assemble the from clause for an HQL query. The class name of each DMO is decapitalized to produce an
4414
    * alias for that object. Form of the clause is:
4415 4415
    * <pre>
4416 4416
    *    from {Buffer0} as {buffer0} [, {Buffer1} as {buffer1} [, ...]]
4417 4417
    * </pre>
4418 4418
    * <p>
4419 4419
    * <b>Known Limitation:</b>
4420
    * At this time, only theta-style joins are supported and as such, only
4421
    * inner joins are supported (there is no way to specify an outer join
4422
    * using theta-join syntax in HQL).
4420
    * At this time, only theta-style joins are supported and as such, only inner joins are supported (there
4421
    * is no way to specify an outer join using theta-join syntax in HQL).
4423 4422
    *
4424 4423
    * @param   buf
4425 4424
    *          String buffer into which clause is assembled.
4426 4425
    * @param   sortCriteria
4427
    *          List of <code>SortCriterion</code> objects which describe the
4428
    *          sort behavior for this query.
4426
    *          All known sort criteria. If a JOIN term is detected in the preprocessed query this list is
4427
    *          simplified to allow a cleaner ORDER BY clause and let the query planner chose a better plan.
4429 4428
    * 
4430 4429
    * @throws  PersistenceException
4431
    *          if there is an error creating the <code>HQLPreprocessor</code>
4432
    *          from which the composite join data are gathered.
4430
    *          if there is an error creating the {@code HQLPreprocessor} from which the composite join data
4431
    *          are gathered.
4433 4432
    */
4434 4433
   protected void assembleFromClause(StringBuilder buf, List<SortCriterion> sortCriteria)
4435 4434
   throws PersistenceException
......
4475 4474
            buf.append(" ");
4476 4475
            joins.add(aJoin);
4477 4476
         }
4477
         
4478
         // now simplify the [sortCriteria] is a server-side JOIN was detected while preprocessing the hql
4479
         List<HQLPreprocessor.PropertyPair> joinPairs = comp.getHQLPreprocessor().getSubstPairs();
4480
         if (joinPairs != null)
4481
         {
4482
            int delCount = 0;
4483
            SortCriterion[] criteria = new SortCriterion[sortCriteria.size()]; 
4484
            sortCriteria.toArray(criteria);
4485
            
4486
            for (int i = 0; i < criteria.length; i++)
4487
            {
4488
               if (criteria[i] == null)
4489
               {
4490
                  continue; // already dropped
4491
               }
4492
               
4493
               for (HQLPreprocessor.PropertyPair pair : joinPairs)
4494
               {
4495
                  if (!pair.getOperator().equals("="))
4496
                  {
4497
                     continue; // ignore properties not joined with = operator 
4498
                  }
4499
                  
4500
                  if (criteria[i].getOriginalName().equals(pair.getLeft()))
4501
                  {
4502
                     for (int j = i + 1; j < criteria.length; j++)
4503
                     {
4504
                        if (criteria[j].getOriginalName().equals(pair.getRight()))
4505
                        {
4506
                           criteria[j] = null;
4507
                           ++ delCount;
4508
                           break; //j
4509
                        }
4510
                     }
4511
                  }
4512
                  else if (criteria[i].getOriginalName().equals(pair.getRight()))
4513
                  {
4514
                     for (int j = i + 1; j < criteria.length; j++)
4515
                     {
4516
                        if (criteria[j].getOriginalName().equals(pair.getLeft()))
4517
                        {
4518
                           criteria[j] = null;
4519
                           ++ delCount;
4520
                           break; //j
4521
                        }
4522
                     }
4523
                  }
4524
               }
4525
            }
4526
            
4527
            // check the remaining criteria
4528
            if (delCount != 0)
4529
            {
4530
               for (int i = sortCriteria.size() - 1; i >= 0; i--)
4531
               {
4532
                  if (criteria[i] == null)
4533
                  {
4534
                     sortCriteria.remove(i);
4535
                  }
4536
               }
4537
            }
4538
         }
4478 4539
      }
4479 4540
   }
4480 4541
   
......
4612 4673
   }
4613 4674
   
4614 4675
   /**
4615
    * Assemble the <code>order by</code> clause for an HQL query.  Uses the
4616
    * form:
4617
    * <pre>
4618
    *   order by {{dmo.property} {asc/desc}} [, ...]
4619
    * </pre>
4676
    * Assemble the {@code order by} clause for an HQL query.
4620 4677
    * <p>
4621
    * Any text-based sort criteria are augmented with the necessary upper()
4622
    * and rtrim() functions.
4623
    *
4624
    * @param   buf
4625
    *          String buffer into which clause is assembled.
4626
    *
4627
    * @return  List of <code>SortCriterion</code> objects which describe the
4628
    *          sort behavior for this query.
4678
    * Any text-based sort criteria are augmented with the necessary upper() and rtrim() functions.
4679
    *
4680
    * @return  List of {@code SortCriterion} objects which describe the sort behavior for this query.
4629 4681
    *
4630 4682
    * @throws  PersistenceException
4631
    *          if the raw sort clause provided at construction contains any
4632
    *          unqualified property names;  if the raw sort clause contains
4633
    *          a reference to an unrecognized record buffer.
4683
    *          if the raw sort clause provided at construction contains any unqualified property names;
4684
    *          if the raw sort clause contains a reference to an unrecognized record buffer.
4634 4685
    */
4635
   protected List<SortCriterion> assembleOrderByClause(StringBuilder buf)
4686
   protected List<SortCriterion> assembleOrderByClause()
4636 4687
   throws PersistenceException
4637 4688
   {
4638 4689
      if (sort == null && dynamicSorts == null)
......
4641 4692
      }
4642 4693
      
4643 4694
      List<SortCriterion> ret = new ArrayList<>();
4644
      buf.append("order by ");
4645 4695
      
4646 4696
      if (dynamicSorts != null)
4647 4697
      {
......
4654 4704
               dynSort.append(", ");
4655 4705
            }
4656 4706
         }
4657
         ret.addAll(assembleOrderByClauseNoPreamble(buf, dynSort.toString()));
4707
         ret.addAll(assembleOrderByClause(dynSort.toString()));
4658 4708
         
4659 4709
         if (sort == null)
4660 4710
         {
4661 4711
            return ret;
4662 4712
         }
4663
         else
4664
         {
4665
            buf.append(", ");
4666
         }
4667 4713
      }
4668 4714
      
4669
      ret.addAll(assembleOrderByClauseNoPreamble(buf, sort));
4715
      ret.addAll(assembleOrderByClause(sort));
4670 4716
      return ret;
4671 4717
   }
4672 4718
   
4673 4719
   /**
4674
    * Assemble the <code>order by</code> clause for an HQL query, sans the
4675
    * &quot;order by&quot; preamble.  Uses the
4676
    * form:
4720
    * Generates the {@code order by} clause starting from the list of criteria, including the "order by"
4721
    * keyword. Uses the form:
4677 4722
    * <pre>
4678
    *   {{dmo.property} {asc/desc}} [, ...]
4723
    *   order by {{dmo.property} {asc/desc}} [, ...]
4679 4724
    * </pre>
4680 4725
    * <p>
4681
    * Any text-based sort criteria are augmented with the necessary upper()
4682
    * and rtrim() functions.
4683 4726
    *
4727
    * @param   sortCriteria
4728
    *          The list of criteria to be added.
4684 4729
    * @param   buf
4685
    *          String buffer into which clause is assembled.
4730
    *          The string builder to add the result.
4731
    */
4732
   private void generateOrderBy(List<SortCriterion> sortCriteria, StringBuilder buf)
4733
   {
4734
      boolean orderBy = true;
4735
      for (SortCriterion criterion : sortCriteria)
4736
      {
4737
         if (orderBy)
4738
         {
4739
            buf.append(" order by ");
4740
            orderBy = false;
4741
         }
4742
         else
4743
         {
4744
            buf.append(", ");
4745
         }
4746
         buf.append(criterion.toString());
4747
      }
4748
   }
4749
   
4750
   /**
4751
    * Assemble the {@code order by} clause for an HQL query.
4752
    * <p>
4753
    * Any text-based sort criteria are augmented with the necessary upper() and rtrim() functions.
4754
    *
4686 4755
    * @param   sort
4687 4756
    *          Raw sort clause to parse and augment if necessary.
4688 4757
    *
4689
    * @return  List of <code>SortCriterion</code> objects which describe the
4690
    *          sort behavior for this query.
4758
    * @return  List of {@code SortCriterion} objects which describe the sort behavior for this query.
4691 4759
    *
4692 4760
    * @throws  PersistenceException
4693
    *          if <code>sort</code> contains any unqualified property names;
4694
    *          if <code>sort</code> clause contains a reference to an
4695
    *          unrecognized record buffer.
4761
    *          if {@code sort} contains any unqualified property names;
4762
    *          if {@code sort} clause contains a reference to an unrecognized record buffer.
4696 4763
    */
4697
   protected List<SortCriterion> assembleOrderByClauseNoPreamble(StringBuilder buf, String sort)
4764
   protected List<SortCriterion> assembleOrderByClause(String sort)
4698 4765
   throws PersistenceException
4699 4766
   {
4700 4767
      List<SortCriterion> sortCriteria = buildSortCriteria(sort);
4701 4768
      
4702
      // Assemble the order by clause, given the list of SortCriterion objects.
4703
      return assembleOrderByClauseNoPreamble(buf, sortCriteria);
4769
      // assemble the order by clause, given the list of SortCriterion objects.
4770
      return assembleOrderByClause(sortCriteria);
4704 4771
   }
4705 4772
   
4706 4773
   /**
4707
    * Returns a list <code>SortCriterion</code> objects build from the given
4708
    * sort clause.
4774
    * Returns a list <code>SortCriterion</code> objects build from the given sort clause.
4709 4775
    *
4710 4776
    * @param   sort
4711 4777
    *          Raw sort clause to parse and augment if necessary.
......
4721 4787
   protected List<SortCriterion> buildSortCriteria(String sort)
4722 4788
   throws PersistenceException
4723 4789
   {
4724
      // Map record buffers used in the sort clause to their identifying
4725
      // aliases.
4790
      // map record buffers used in the sort clause to their identifying aliases
4726 4791
      Map<String, RecordBuffer> aliases = new HashMap<>();
4727 4792
      Iterator<QueryComponent> iter = components();
4728 4793
      while (iter.hasNext())
......
4797 4862
   }
4798 4863
   
4799 4864
   /**
4800
    * Assemble the <code>order by</code> clause for an HQL query, sans the
4801
    * &quot;order by&quot; preamble.  Uses the
4802
    * form:
4803
    * <pre>
4804
    *   {{dmo.property} {asc/desc}} [, ...]
4805
    * </pre>
4865
    * Assemble the {@code order by} clause for an HQL query.
4806 4866
    * <p>
4807
    * Any text-based sort criteria are augmented with the necessary upper()
4808
    * and rtrim() functions.
4867
    * Any text-based sort criteria are augmented with the necessary upper() and rtrim() functions.
4809 4868
    *
4810
    * @param   buf
4811
    *          String buffer into which clause is assembled.
4812 4869
    * @param   sortCriteria
4813
    *          A list of <code>SortCriterion</code> objects which describe
4814
    *          the sorting to be applied.
4870
    *          A list of {@code SortCriterion} objects which describe the sorting to be applied.
4815 4871
    *
4816
    * @return  List of <code>SortCriterion</code> objects which describe the
4817
    *          sort behavior for this query.
4872
    * @return  List of {@code SortCriterion} objects which describe the sort behavior for this query.
4818 4873
    */
4819
   protected List<SortCriterion> assembleOrderByClauseNoPreamble(StringBuilder buf,
4820
                                                                 List<SortCriterion> sortCriteria)
4874
   protected List<SortCriterion> assembleOrderByClause(List<SortCriterion> sortCriteria)
4821 4875
   {
4822 4876
      RecordBuffer buffer = getRecordBuffers()[0];
4823 4877
      boolean multiplex = (buffer.getMultiplexID() != null);
4824
      List<SortCriterion> workList = null;
4878
      List<SortCriterion> workList;
4825 4879
      
4826 4880
      if (sortCriteria == null)
4827 4881
      {
......
4834 4888
            return null;
4835 4889
         }
4836 4890
      }
4837
      
4838
      if (workList == null)
4891
      else
4839 4892
      {
4840 4893
         workList = new ArrayList<>(sortCriteria.size() + 1);
4841 4894
      }
4842 4895
      
4843
      workList.addAll(sortCriteria);
4844
      
4845 4896
      if (multiplex)
4846 4897
      {
4847
//         String schema = buffer.getSchema();
4848 4898
         Class<? extends DataModelObject> dmoIface = buffer.getDMOInterface();
4849 4899
         Class<? extends Record> dmoClass = buffer.getDMOImplementationClass();
4900
         String text = buffer.getDMOAlias() + "." + TemporaryBuffer.MULTIPLEX_FIELD_NAME + " asc";
4850 4901
         
4851
         StringBuilder sb = new StringBuilder();
4852
         sb.append(buffer.getDMOAlias());
4853
         sb.append(".");
4854
         sb.append(TemporaryBuffer.MULTIPLEX_FIELD_NAME);
4855
         sb.append(" asc");
4856 4902
         try
4857 4903
         {
4858
            SortCriterion multiCrit = new SortCriterion(buffer,
4859
                                                        sb.toString(),
4860
                                                        dmoIface,
4861
                                                        dmoClass);
4862
            workList.add(0, multiCrit);
4904
            workList.add(new SortCriterion(buffer, text, dmoIface, dmoClass));
4863 4905
         }
4864 4906
         catch (PersistenceException exc)
4865 4907
         {
......
4867 4909
         }
4868 4910
      }
4869 4911
      
4870
      Iterator<SortCriterion> iter = workList.iterator();
4871
      for (int i = 0; iter.hasNext(); i++)
4912
      if (sortCriteria != null)
4872 4913
      {
4873
         SortCriterion crit = iter.next();
4874
         
4875
         if (i > 0)
4876
         {
4877
            buf.append(", ");
4878
         }
4879
         
4880
         buf.append(crit.toSortExpression(false));
4914
         workList.addAll(sortCriteria);
4881 4915
      }
4882 4916
      
4883
      return sortCriteria;
4917
      return workList;
4884 4918
   }
4885 4919
   
4886 4920
   /**
......
6331 6365
   private String assembleHQL()
6332 6366
   throws PersistenceException
6333 6367
   {
6368
      // need to put together order by clause first, as the sort criteria determined in this analysis may be
6369
      // needed when composing from clause and where clause
6370
      List<SortCriterion> sortCriteria = assembleOrderByClause();
6371
      
6334 6372
      StringBuilder buf = new StringBuilder();
6335
      
6336
      // Need to put together order by clause first, as the sort criteria
6337
      // determined in this analysis may be needed when composing from clause
6338
      // and where clause.
6339
      List<SortCriterion> sortCriteria = assembleOrderByClause(buf);
6340
      String orderBy = buf.toString();
6341
      buf.setLength(0);
6342 6373
      assembleSelectClause(buf);
6343 6374
      assembleFromClause(buf, sortCriteria);
6344 6375
      buf.append(assembleWhereClause(sortCriteria).toFinalExpression());
6345
      buf.append(orderBy);
6376
      generateOrderBy(sortCriteria, buf);
6346 6377
      
6347 6378
      return buf.toString().trim();
6348 6379
   }
src/com/goldencode/p2j/persist/PresortQuery.java 2020-10-01 13:48:40 +0000
5 5
**
6 6
** Copyright (c) 2004-2020, Golden Code Development Corporation.
7 7
**
8
** -#- -I- --Date-- --JPRM-- --------------------------Description---------------------------
8
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
9 9
** 001 ECF 20060103   @23795 Created initial version. A specialized
10 10
**                           preselect query which uses client-side record
11 11
**                           sorting to presort query results before loop
......
88 88
** 030 OM  20180515          Added dynamic filters and dynamic sort.
89 89
** 031 ECF 20181106          Added runtime support for {FIRST|LAST}-OF methods.
90 90
** 032 ECF 20200906          New ORM implementation.
91
** 033 OM  20201001          Dropped redundant ORDER BY elements in multi-table queries.
91 92
*/
92 93

  
93 94
/*
......
1473 1474
      
1474 1475
      buf.append(" ");
1475 1476
   }
1476

  
1477
   
1477 1478
   /**
1478
    * Assemble the <code>order by</code> clause for an HQL query.  Uses the
1479
    * form (ordered only by primary keys):
1480
    * <pre>
1481
    *   order by {dmo.id asc} [, ...]
1482
    * </pre>
1483
    * <p>
1484
    *
1485
    * @param   buf
1486
    *          String buffer into which clause is assembled.
1487
    *
1488
    * @return  List of <code>SortCriterion</code> objects which describe the
1489
    *          sort behavior for this query.
1479
    * Assemble the {@code order by} clause for an HQL query.
1480
    *
1481
    * @return  List of <code>SortCriterion</code> objects which describe the sort behavior for this query.
1490 1482
    *
1491 1483
    * @throws  PersistenceException
1492 1484
    *          never.
1493 1485
    */
1494
   protected List<SortCriterion> assembleOrderByClause(StringBuilder buf)
1486
   protected List<SortCriterion> assembleOrderByClause()
1495 1487
   throws PersistenceException
1496 1488
   {
1497
      buf.append("order by ");
1498
      
1499
      List<SortCriterion> sortCriteria =
1500
         (sort == null) ? new ArrayList<>() : super.buildSortCriteria(sort);
1489
      List<SortCriterion> sortCriteria = (sort == null) ? new ArrayList<>() : super.buildSortCriteria(sort);
1501 1490
      
1502 1491
      Iterator<QueryComponent> iter = components();
1503 1492
      while (iter.hasNext())
......
1514 1503
         sortCriteria.add(crit);
1515 1504
      }
1516 1505
      
1517
      return assembleOrderByClauseNoPreamble(buf, sortCriteria);
1506
      return assembleOrderByClause(sortCriteria);
1518 1507
   }
1519 1508
}
src/com/goldencode/p2j/persist/SortCriterion.java 2020-10-01 13:53:57 +0000
4 4
**
5 5
** Copyright (c) 2004-2020, Golden Code Development Corporation.
6 6
**
7
** -#- -I- --Date-- --JPRM-- ----------------------------Description----------------------------
7
** -#- -I- --Date-- --JPRM-- -----------------------------------Description-----------------------------------
8 8
** 001 ECF 20060802   @28346 Created initial version. Based upon an inner
9 9
**                           class previously within HQLHelper.
10 10
** 002 ECF 20060831   @29089 Added support for sorting by an indexed
......
88 88
**     CA  20200306          Changed H033 to rely on 'WHERE_WITH_NULLS' system property, to 
89 89
**                           activate the 'withNull in toWhereExpression.
90 90
** 035 ECF 20200906          New ORM implementation.
91
** 036 OM  20201001          Dropped redundant ORDER BY elements in multi-table queries.
91 92
*/
92 93

  
93 94
/*
......
270 271
    *          Record buffer.
271 272
    * @param   text
272 273
    *          Text representation of sort component, as provided by query.
273
//    * @param   schema
274
//    *          Name of database schema.
275 274
    * @param   dmoIface
276 275
    *          DMO interface.
277 276
    * @param   dmoClass
......
283 282
    */
284 283
   SortCriterion(RecordBuffer buffer,
285 284
                 String text,
286
                /* String schema,*/
287 285
                 Class<? extends DataModelObject> dmoIface,
288 286
                 Class<? extends Record> dmoClass)
289 287
   throws PersistenceException
290 288
   {
291
      this(buffer.getDialect(), buffer.getDatabase(), text, /*schema,*/ dmoIface, dmoClass, false);
289
      this(buffer.getDialect(), buffer.getDatabase(), text, dmoIface, dmoClass, false);
292 290
   }
293 291
   
294 292
   /**
......
310 308
    *          The target database.
311 309
    * @param   text
312 310
    *          Text representation of sort component, as provided by query.
313
//    * @param   schema
314
//    *          Name of database schema.
315 311
    * @param   dmoIface
316 312
    *          DMO interface.
317 313
    * @param   dmoClass
......
324 320
   SortCriterion(Dialect dialect,
325 321
                 Database database,
326 322
                 String text,
327
                 /*String schema,*/
328 323
                 Class<? extends DataModelObject> dmoIface,
329 324
                 Class<? extends Record> dmoClass)
330 325
   throws PersistenceException
331 326
   {
332
      this(dialect, database, text, /*schema,*/ dmoIface, dmoClass, true);
327
      this(dialect, database, text, dmoIface, dmoClass, true);
333 328
   }
334 329
   
335 330
   /**
......
346 341
    *          The target database.
347 342
    * @param   text
348 343
    *          Text representation of sort component, as provided by query.
349
//    * @param   schema
350
//    *          Name of database schema.
351 344
    * @param   dmoIface
352 345
    *          DMO interface.
353 346
    * @param   dmoClass
......
362 355
   SortCriterion(Dialect dialect,
363 356
                 Database database,
364 357
                 String text,
365
                 /*String schema,*/
366 358
                 Class<? extends DataModelObject> dmoIface,
367 359
                 Class<? extends Record> dmoClass,
368 360
                 boolean internStrings)