Skip to content

Commit 318906d

Browse files
authored
Merge pull request #1807 from wheels-dev/Wheels-Optimization
Update $executeQuery function for better optimization
2 parents a5ecece + aa02c4e commit 318906d

File tree

2 files changed

+112
-83
lines changed

2 files changed

+112
-83
lines changed

core/src/wheels/model/adapters/Base.cfc

Lines changed: 102 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,121 @@ component output=false extends="wheels.Global"{
22

33
public struct function $executeQuery(
44
required struct queryAttributes,
5-
required array sql,
5+
required array sql,
66
required boolean parameterize,
77
required numeric limit,
88
required numeric offset,
99
required string comment,
1010
required string debugName,
1111
required string primaryKey
1212
) {
13-
// Since we allow the developer to pass in the name to use for the query variable we need to avoid name clashing.
14-
// We do this by putting all our own variables inside a $wheels struct.
15-
local.$wheels = {};
16-
local.$wheels.rv = {};
17-
18-
if(structKeyExists(arguments.queryAttributes, "DATASOURCE") && len(arguments.queryAttributes.DATASOURCE)){
19-
local.info = $dbinfo(
20-
type = "version",
21-
datasource = arguments.queryAttributes.DATASOURCE);
22-
} else {
23-
local.info = $dbinfo(
24-
type = "version",
13+
// local variables
14+
local.wheels = { rv: {} };
15+
local.newLine = chr(13) & chr(10);
16+
local.args = arguments;
17+
local.sqlArray = args.sql;
18+
local.sqlLen = arrayLen(sqlArray);
19+
20+
// Detect datasource info once
21+
local.ds = args.queryAttributes;
22+
local.dsInfo = ( structKeyExists(ds, "DATASOURCE") && len(ds.DATASOURCE) )
23+
? $dbinfo(type="version", datasource=ds.DATASOURCE)
24+
: $dbinfo(
25+
type = "version",
2526
datasource = application.wheels.dataSourceName,
26-
username = application.wheels.dataSourceUserName,
27-
password = application.wheels.dataSourcePassword
27+
username = application.wheels.dataSourceUserName,
28+
password = application.wheels.dataSourcePassword
2829
);
29-
}
30-
cfquery(attributeCollection=arguments.queryAttributes){
31-
local.$wheels.pos = 0;
32-
33-
for (local.$wheels.i in arguments.sql) {
34-
local.$wheels.pos += 1;
35-
if (isStruct(local.$wheels.i)) {
36-
local.$wheels.queryParamAttributes = $queryParams(local.$wheels.i);
37-
if (!isBinary(local.$wheels.i.value) && local.$wheels.i.value == "null" && local.$wheels.pos > 1 &&
38-
(right(arguments.sql[local.$wheels.pos - 1], 2) == "IS" || right(arguments.sql[local.$wheels.pos - 1], 6) == "IS NOT")) {
39-
writeOutput("NULL");
40-
} else if (structKeyExists(local.$wheels.queryParamAttributes, "list")) {
41-
if (arguments.parameterize) {
42-
writeOutput("(");
43-
cfqueryParam(attributeCollection=local.$wheels.queryParamAttributes);
44-
writeOutput(")");
45-
} else {
46-
writeOutput("(" & preserveSingleQuotes(local.$wheels.i.value) & ")");
47-
}
48-
} else {
49-
if (arguments.parameterize) {
50-
cfqueryParam(attributeCollection=local.$wheels.queryParamAttributes);
51-
} else {
52-
writeOutput($quoteValue(str=local.$wheels.i.value, sqlType=local.$wheels.i.type));
53-
}
54-
}
55-
} else {
56-
local.$wheels.i = replace(preserveSingleQuotes(local.$wheels.i), "[[comma]]", ",", "all");
57-
writeOutput(preserveSingleQuotes(local.$wheels.i));
58-
}
59-
writeOutput(chr(13) & chr(10));
60-
}
61-
62-
if(arguments.limit){
63-
if(FindNoCase("Oracle", local.info.database_productname)){
64-
if(arguments.offset){
65-
writeOutput("OFFSET " & arguments.offset & " ROWS" & chr(13) & chr(10) & "FETCH NEXT " & arguments.limit & " ROWS ONLY");
66-
} else {
67-
writeOutput("FETCH FIRST " & arguments.limit & " ROWS ONLY");
30+
31+
// Build query
32+
cfquery(attributeCollection = args.queryAttributes) {
33+
local.pos = 1;
34+
local.prev = "";
35+
36+
for (; pos <= sqlLen; pos++) {
37+
local.part = sqlArray[pos];
38+
39+
if (isStruct(part)) {
40+
local.qp = $queryParams(part);
41+
42+
// Handle NULL for "IS NULL" or "IS NOT NULL"
43+
if (
44+
!isBinary(part.value) &&
45+
part.value == "null" &&
46+
pos > 1 &&
47+
( right(prev, 2) == "IS" || right(prev, 6) == "IS NOT" )
48+
) {
49+
writeOutput("NULL");
50+
}
51+
// Handle parameter lists "(?,?,?)"
52+
else if (structKeyExists(qp, "list")) {
53+
writeOutput("(");
54+
if (args.parameterize) {
55+
cfqueryParam(attributeCollection = qp);
56+
} else {
57+
writeOutput("(" & preserveSingleQuotes(part.value) & ")");
58+
}
59+
writeOutput(")");
60+
}
61+
// Normal parameter
62+
else {
63+
if (args.parameterize) {
64+
cfqueryParam(attributeCollection = qp);
65+
} else {
66+
writeOutput($quoteValue(str = part.value, sqlType = part.type));
67+
}
68+
}
69+
}
70+
else {
71+
// regular SQL string part
72+
part = replace(preserveSingleQuotes(part), "[[comma]]", ",", "all");
73+
writeOutput(preserveSingleQuotes(part));
74+
}
75+
76+
writeOutput(newLine);
77+
prev = part;
6878
}
69-
} else {
70-
writeOutput("LIMIT " & arguments.limit);
71-
if (arguments.offset) {
72-
writeOutput(chr(13) & chr(10) & "OFFSET " & arguments.offset);
79+
80+
// LIMIT / OFFSET logic
81+
if (args.limit) {
82+
if (findNoCase("Oracle", dsInfo.database_productname)) {
83+
if (args.offset) {
84+
writeOutput("OFFSET " & args.offset & " ROWS" & newLine & "FETCH NEXT " & args.limit & " ROWS ONLY");
85+
} else {
86+
writeOutput("FETCH FIRST " & args.limit & " ROWS ONLY");
87+
}
88+
} else {
89+
writeOutput("LIMIT " & args.limit);
90+
if (args.offset) {
91+
writeOutput(newLine & "OFFSET " & args.offset);
92+
}
93+
}
7394
}
95+
96+
// Comment block
97+
if (len(args.comment)) {
98+
writeOutput(args.comment);
99+
}
100+
}
101+
102+
// Retrieve debug query if needed
103+
if (structKeyExists(local, args.debugName)) {
104+
wheels.rv.query = local[args.debugName];
74105
}
75-
}
76-
77-
if (len(arguments.comment)) {
78-
writeOutput(arguments.comment);
79-
}
80-
}
81-
82-
if(StructKeyExists(local, arguments.debugName)){
83-
local.$wheels.rv.query = local[arguments.debugName];
84-
}
85-
// Get / set the primary key name / value when Lucee / ACF cannot retrieve it for us.
86-
local.$wheels.id = $identitySelect(
87-
primaryKey = arguments.primaryKey,
88-
queryAttributes = arguments.queryAttributes,
89-
result = local.$wheels.result
106+
107+
// Manual identity retrieval for Lucee / ACF
108+
wheels.id = $identitySelect(
109+
primaryKey = args.primaryKey,
110+
queryAttributes = args.queryAttributes,
111+
result = wheels.result
90112
);
91-
if (StructKeyExists(local.$wheels, "id") && IsStruct(local.$wheels.id) && !StructIsEmpty(local.$wheels.id)) {
92-
StructAppend(local.$wheels.result, local.$wheels.id);
113+
114+
if (structKeyExists(wheels,"id") && isStruct(wheels.id) && !structIsEmpty(wheels.id)) {
115+
structAppend(wheels.result, wheels.id);
93116
}
94117

95-
local.$wheels.rv.result = local.$wheels.result;
96-
return local.$wheels.rv;
118+
wheels.rv.result = wheels.result;
119+
return wheels.rv;
97120
}
98121

99122
/**
@@ -126,7 +149,7 @@ component output=false extends="wheels.Global"{
126149
required struct result,
127150
required string primaryKey
128151
) {
129-
var query = {};
152+
local.query = {};
130153
local.sql = Trim(arguments.result.sql);
131154
if (Left(local.sql, 11) == "INSERT INTO" && !StructKeyExists(arguments.result, $generatedKey())) {
132155
local.startPar = Find("(", local.sql) + 1;
@@ -507,7 +530,7 @@ component output=false extends="wheels.Global"{
507530
local.queryAttributes.dataSource = arguments.dataSource;
508531
local.queryAttributes.username = variables.username;
509532
local.queryAttributes.password = variables.password;
510-
local.queryAttributes.result = "local.$wheels.result";
533+
local.queryAttributes.result = "local.wheels.result";
511534
local.queryAttributes.name = "local." & arguments.$debugName;
512535
if (StructKeyExists(local.queryAttributes, "username") && !Len(local.queryAttributes.username)) {
513536
StructDelete(local.queryAttributes, "username");

core/src/wheels/tests_testbox/specs/global/dbinfoSpec.cfc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ component extends="wheels.Testbox" {
9696
local.ourTables = [];
9797
for (local.row in local.result) {
9898
if (findNoCase(variables.prefix, local.row.table_name) &&
99-
local.row.table_type == "TABLE") {
99+
listFindNoCase("TABLE,BASE TABLE", local.row.table_type)) {
100100
arrayAppend(local.ourTables, local.row);
101101
}
102102
}
@@ -115,7 +115,7 @@ component extends="wheels.Testbox" {
115115
local.ourTables = [];
116116
for (local.row in local.result) {
117117
if (findNoCase(variables.prefix, local.row.table_name) &&
118-
(local.row.table_type == "TABLE" || local.row.table_type == "VIEW")) {
118+
(listFindNoCase("TABLE,BASE TABLE", local.row.table_type) || local.row.table_type == "VIEW")) {
119119
arrayAppend(local.ourTables, local.row);
120120
}
121121
}
@@ -134,7 +134,7 @@ component extends="wheels.Testbox" {
134134
local.ourTableNames = [];
135135
for (local.row in local.result) {
136136
if (findNoCase(variables.prefix, local.row.table_name) &&
137-
(local.row.table_type == "TABLE" || local.row.table_type == "VIEW")) {
137+
(listFindNoCase("TABLE,BASE TABLE", local.row.table_type) || local.row.table_type == "VIEW")) {
138138
arrayAppend(local.ourTableNames, local.row.table_name);
139139
}
140140
}
@@ -186,7 +186,13 @@ component extends="wheels.Testbox" {
186186
variables.varcharType = "TEXT";
187187
} else {
188188
// Default (H2, etc.)
189-
variables.identityColumnType = "INT NOT NULL IDENTITY";
189+
local.dbVersion = listToArray(local.dbInfo["DATABASE_VERSION"], " ")[1];
190+
if(local.dbVersion eq '2.1.214'){
191+
variables.identityColumnType = "INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY";
192+
}
193+
else if(local.dbVersion eq '1.3.172'){
194+
variables.identityColumnType = "int NOT NULL IDENTITY";
195+
}
190196
variables.varcharType = "VARCHAR";
191197
}
192198
}

0 commit comments

Comments
 (0)