Dropped_redundant_ORDER-BY_elements.patch
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 |
* "order by" 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 |
* "order by" 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) |