diff --git a/qqq-backend-core/pom.xml b/qqq-backend-core/pom.xml
index 60561f25..c9a3c8f5 100644
--- a/qqq-backend-core/pom.xml
+++ b/qqq-backend-core/pom.xml
@@ -192,6 +192,13 @@
2.3.2
+
+
+ com.mchange
+ mchange-commons-java
+ 0.3.0
+
+
org.apache.logging.log4j
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportAction.java
index e14de682..9c5628f9 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportAction.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/ExportAction.java
@@ -44,6 +44,7 @@ import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportInput;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportOutput;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
@@ -216,7 +217,8 @@ public class ExportAction
}
queryInput.getFilter().setLimit(exportInput.getLimit());
queryInput.setShouldTranslatePossibleValues(true);
- queryInput.withQueryHint(QueryInput.QueryHint.POTENTIALLY_LARGE_NUMBER_OF_RESULTS);
+ queryInput.withQueryHint(QueryHint.POTENTIALLY_LARGE_NUMBER_OF_RESULTS);
+ queryInput.withQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
/////////////////////////////////////////////////////////////////
// tell this query that it needs to put its output into a pipe //
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java
index 3c2ace5c..a984bed3 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/actions/reporting/GenerateReportAction.java
@@ -59,6 +59,7 @@ import com.kingsrook.qqq.backend.core.model.actions.reporting.ExportInput;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportFormat;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportInput;
import com.kingsrook.qqq.backend.core.model.actions.reporting.ReportOutput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.JoinsContext;
@@ -417,7 +418,8 @@ public class GenerateReportAction extends AbstractQActionFunction transactionsPerTable = new HashMap<>();
-
- // todo not commit - remove instance & session - use Context
-
-
- boolean useTransactionsAsConnectionPool = false;
-
-
-
- /*******************************************************************************
- **
- *******************************************************************************/
- private QBackendTransaction getTransaction(String tableName)
- {
- /////////////////////////////////////////////////////////////
- // mmm, this does cut down on connections used - //
- // especially seems helpful in big exports. //
- // but, let's just start using connection pools instead... //
- /////////////////////////////////////////////////////////////
- if(useTransactionsAsConnectionPool)
- {
- try
- {
- if(!transactionsPerTable.containsKey(tableName))
- {
- transactionsPerTable.put(tableName, QBackendTransaction.openFor(new InsertInput(tableName)));
- }
-
- return (transactionsPerTable.get(tableName));
- }
- catch(Exception e)
- {
- LOG.warn("Error opening transaction for table", logPair("tableName", tableName));
- }
- }
-
- return null;
- }
-
/*******************************************************************************
@@ -601,7 +561,7 @@ public class QPossibleValueTranslator
QueryInput queryInput = new QueryInput();
queryInput.setTableName(tableName);
queryInput.setFilter(new QQueryFilter().withCriteria(new QFilterCriteria(idField, QCriteriaOperator.IN, page)));
- queryInput.setTransaction(getTransaction(tableName));
+ queryInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// when querying for possible values, we do want to generate their display values, which makes record labels, which are usually used as PVS labels //
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/QueryHint.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/QueryHint.java
new file mode 100644
index 00000000..8c7050f2
--- /dev/null
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/QueryHint.java
@@ -0,0 +1,38 @@
+/*
+ * QQQ - Low-code Application Framework for Engineers.
+ * Copyright (C) 2021-2024. Kingsrook, LLC
+ * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
+ * contact@kingsrook.com
+ * https://github.com/Kingsrook/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.kingsrook.qqq.backend.core.model.actions.tables;
+
+
+/*******************************************************************************
+ ** Information about the query that an application (or qqq service) may know and
+ ** want to tell the backend, that can help influence how the backend processes
+ ** query.
+ **
+ ** For example, a query with potentially a large result set, for MySQL backend,
+ ** we may want to configure the result set to stream results rather than do its
+ ** default in-memory thing. See RDBMSQueryAction for usage.
+ *******************************************************************************/
+public enum QueryHint
+{
+ POTENTIALLY_LARGE_NUMBER_OF_RESULTS,
+ MAY_USE_READ_ONLY_BACKEND
+}
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/aggregate/AggregateInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/aggregate/AggregateInput.java
index 862ebcf6..9d69e5ac 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/aggregate/AggregateInput.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/aggregate/AggregateInput.java
@@ -23,8 +23,10 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.aggregate;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
@@ -44,6 +46,8 @@ public class AggregateInput extends AbstractTableActionInput
private List queryJoins = null;
+ private EnumSet queryHints = EnumSet.noneOf(QueryHint.class);
+
/*******************************************************************************
@@ -302,4 +306,78 @@ public class AggregateInput extends AbstractTableActionInput
return (this);
}
+
+
+ /*******************************************************************************
+ ** Getter for queryHints
+ *******************************************************************************/
+ public EnumSet getQueryHints()
+ {
+ return (this.queryHints);
+ }
+
+
+
+ /*******************************************************************************
+ ** Setter for queryHints
+ *******************************************************************************/
+ public void setQueryHints(EnumSet queryHints)
+ {
+ this.queryHints = queryHints;
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public AggregateInput withQueryHints(EnumSet queryHints)
+ {
+ this.queryHints = queryHints;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public AggregateInput withQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ this.queryHints = EnumSet.noneOf(QueryHint.class);
+ }
+ this.queryHints.add(queryHint);
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public AggregateInput withoutQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints != null)
+ {
+ this.queryHints.remove(queryHint);
+ }
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** null-safely check if query hints map contains the specified hint
+ *******************************************************************************/
+ public boolean hasQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ return (false);
+ }
+
+ return (queryHints.contains(queryHint));
+ }
}
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/count/CountInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/count/CountInput.java
index e1994d8b..a4f47090 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/count/CountInput.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/count/CountInput.java
@@ -23,8 +23,10 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.count;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
@@ -42,6 +44,8 @@ public class CountInput extends AbstractTableActionInput
private List queryJoins = null;
private Boolean includeDistinctCount = false;
+ private EnumSet queryHints = EnumSet.noneOf(QueryHint.class);
+
/*******************************************************************************
@@ -207,4 +211,78 @@ public class CountInput extends AbstractTableActionInput
return (this);
}
+
+
+ /*******************************************************************************
+ ** Getter for queryHints
+ *******************************************************************************/
+ public EnumSet getQueryHints()
+ {
+ return (this.queryHints);
+ }
+
+
+
+ /*******************************************************************************
+ ** Setter for queryHints
+ *******************************************************************************/
+ public void setQueryHints(EnumSet queryHints)
+ {
+ this.queryHints = queryHints;
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public CountInput withQueryHints(EnumSet queryHints)
+ {
+ this.queryHints = queryHints;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public CountInput withQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ this.queryHints = EnumSet.noneOf(QueryHint.class);
+ }
+ this.queryHints.add(queryHint);
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public CountInput withoutQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints != null)
+ {
+ this.queryHints.remove(queryHint);
+ }
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** null-safely check if query hints map contains the specified hint
+ *******************************************************************************/
+ public boolean hasQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ return (false);
+ }
+
+ return (queryHints.contains(queryHint));
+ }
}
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java
index 2cf7872f..711c3280 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/get/GetInput.java
@@ -25,10 +25,12 @@ package com.kingsrook.qqq.backend.core.model.actions.tables.get;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.QueryOrGetInputInterface;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
@@ -60,6 +62,8 @@ public class GetInput extends AbstractTableActionInput implements QueryOrGetInpu
private boolean includeAssociations = false;
private Collection associationNamesToInclude = null;
+ private EnumSet queryHints = EnumSet.noneOf(QueryHint.class);
+
/*******************************************************************************
@@ -462,4 +466,79 @@ public class GetInput extends AbstractTableActionInput implements QueryOrGetInpu
return (this);
}
+
+
+ /*******************************************************************************
+ ** Getter for queryHints
+ *******************************************************************************/
+ public EnumSet getQueryHints()
+ {
+ return (this.queryHints);
+ }
+
+
+
+ /*******************************************************************************
+ ** Setter for queryHints
+ *******************************************************************************/
+ public void setQueryHints(EnumSet queryHints)
+ {
+ this.queryHints = queryHints;
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public GetInput withQueryHints(EnumSet queryHints)
+ {
+ this.queryHints = queryHints;
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public GetInput withQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ this.queryHints = EnumSet.noneOf(QueryHint.class);
+ }
+ this.queryHints.add(queryHint);
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** Fluent setter for queryHints
+ *******************************************************************************/
+ public GetInput withoutQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints != null)
+ {
+ this.queryHints.remove(queryHint);
+ }
+ return (this);
+ }
+
+
+
+ /*******************************************************************************
+ ** null-safely check if query hints map contains the specified hint
+ *******************************************************************************/
+ public boolean hasQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ return (false);
+ }
+
+ return (queryHints.contains(queryHint));
+ }
+
}
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java
index a0e71e19..5a00b1a3 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/model/actions/tables/query/QueryInput.java
@@ -31,12 +31,16 @@ import java.util.Set;
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
import com.kingsrook.qqq.backend.core.actions.reporting.RecordPipe;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.QueryOrGetInputInterface;
/*******************************************************************************
** Input data for the Query action
**
+ ** Todo - maybe make a class between AbstractTableActionInput and {QueryInput,
+ ** CountInput, and AggregateInput}, with common attributes for all of these
+ ** "read" operations (like, queryHints,
*******************************************************************************/
public class QueryInput extends AbstractTableActionInput implements QueryOrGetInputInterface, Cloneable
{
@@ -74,22 +78,6 @@ public class QueryInput extends AbstractTableActionInput implements QueryOrGetIn
- /*******************************************************************************
- ** Information about the query that an application (or qqq service) may know and
- ** want to tell the backend, that can help influence how the backend processes
- ** query.
- **
- ** For example, a query with potentially a large result set, for MySQL backend,
- ** we may want to configure the result set to stream results rather than do its
- ** default in-memory thing. See RDBMSQueryAction for usage.
- *******************************************************************************/
- public enum QueryHint
- {
- POTENTIALLY_LARGE_NUMBER_OF_RESULTS
- }
-
-
-
/*******************************************************************************
**
*******************************************************************************/
@@ -683,4 +671,19 @@ public class QueryInput extends AbstractTableActionInput implements QueryOrGetIn
return (this);
}
+
+
+ /*******************************************************************************
+ ** null-safely check if query hints map contains the specified hint
+ *******************************************************************************/
+ public boolean hasQueryHint(QueryHint queryHint)
+ {
+ if(this.queryHints == null)
+ {
+ return (false);
+ }
+
+ return (queryHints.contains(queryHint));
+ }
+
}
diff --git a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/garbagecollector/GarbageCollectorExtractStep.java b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/garbagecollector/GarbageCollectorExtractStep.java
index 3f4ee4c0..171b4c33 100644
--- a/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/garbagecollector/GarbageCollectorExtractStep.java
+++ b/qqq-backend-core/src/main/java/com/kingsrook/qqq/backend/core/processes/implementations/garbagecollector/GarbageCollectorExtractStep.java
@@ -25,6 +25,7 @@ package com.kingsrook.qqq.backend.core.processes.implementations.garbagecollecto
import java.time.Instant;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.ExtractViaQueryStep;
@@ -66,7 +67,7 @@ public class GarbageCollectorExtractStep extends ExtractViaQueryStep
@Override
protected void customizeInputPreQuery(QueryInput queryInput)
{
- queryInput.withQueryHint(QueryInput.QueryHint.POTENTIALLY_LARGE_NUMBER_OF_RESULTS);
+ queryInput.withQueryHint(QueryHint.POTENTIALLY_LARGE_NUMBER_OF_RESULTS);
}
}
diff --git a/qqq-backend-module-rdbms/pom.xml b/qqq-backend-module-rdbms/pom.xml
index 19d778c3..3e9be513 100644
--- a/qqq-backend-module-rdbms/pom.xml
+++ b/qqq-backend-module-rdbms/pom.xml
@@ -50,6 +50,11 @@
mysql-connector-java
8.0.30
+
+ com.mchange
+ c3p0
+ 0.10.0
+
com.h2database
h2
diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java
index afb3b5d6..082759bc 100644
--- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java
+++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/AbstractRDBMSAction.java
@@ -47,14 +47,19 @@ import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.Aggregate;
+import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.AggregateInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.GroupBy;
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.QFilterOrderByAggregate;
import com.kingsrook.qqq.backend.core.model.actions.tables.aggregate.QFilterOrderByGroupBy;
+import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
+import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.JoinsContext;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterOrderBy;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
+import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryJoin;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.expressions.AbstractFilterExpression;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
@@ -135,11 +140,38 @@ public abstract class AbstractRDBMSAction
/*******************************************************************************
** Get a database connection, per the backend in the request.
+ **
+ ** Note that it may be a connection to a read-only backend, per query-hints,
+ ** and backend settings.
*******************************************************************************/
- public static Connection getConnection(AbstractTableActionInput qTableRequest) throws SQLException
+ public static Connection getConnection(AbstractTableActionInput tableActionInput) throws SQLException
{
- ConnectionManager connectionManager = new ConnectionManager();
- return connectionManager.getConnection((RDBMSBackendMetaData) qTableRequest.getBackend());
+ RDBMSBackendMetaData backend = (RDBMSBackendMetaData) tableActionInput.getBackend();
+
+ boolean useReadOnly = false;
+ if(tableActionInput instanceof QueryInput queryInput)
+ {
+ useReadOnly = queryInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
+ }
+ else if(tableActionInput instanceof CountInput countInput)
+ {
+ useReadOnly = countInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
+ }
+ else if(tableActionInput instanceof GetInput getInput)
+ {
+ useReadOnly = getInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
+ }
+ else if(tableActionInput instanceof AggregateInput aggregateInput)
+ {
+ useReadOnly = aggregateInput.hasQueryHint(QueryHint.MAY_USE_READ_ONLY_BACKEND);
+ }
+
+ if(useReadOnly && backend.getReadOnlyBackendMetaData() != null)
+ {
+ return ConnectionManager.getConnection(backend.getReadOnlyBackendMetaData());
+ }
+
+ return ConnectionManager.getConnection(backend);
}
diff --git a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java
index 2a88d43e..101d96f4 100644
--- a/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java
+++ b/qqq-backend-module-rdbms/src/main/java/com/kingsrook/qqq/backend/module/rdbms/actions/RDBMSInsertAction.java
@@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.module.rdbms.actions;
import java.io.Serializable;
import java.sql.Connection;
+import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -53,9 +54,12 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
*******************************************************************************/
public InsertOutput execute(InsertInput insertInput) throws QException
{
- InsertOutput rs = new InsertOutput();
+ InsertOutput rs = new InsertOutput();
QTableMetaData table = insertInput.getTable();
+ Connection connection = null;
+ boolean needToCloseConnection = false;
+
try
{
List insertableFields = table.getFields().values().stream()
@@ -72,8 +76,6 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
List outputRecords = new ArrayList<>();
rs.setRecords(outputRecords);
- Connection connection;
- boolean needToCloseConnection = false;
if(insertInput.getTransaction() != null && insertInput.getTransaction() instanceof RDBMSTransaction rdbmsTransaction)
{
connection = rdbmsTransaction.getConnection();
@@ -84,87 +86,77 @@ public class RDBMSInsertAction extends AbstractRDBMSAction implements InsertInte
needToCloseConnection = true;
}
- try
+ for(List page : CollectionUtils.getPages(insertInput.getRecords(), QueryManager.PAGE_SIZE))
{
- for(List page : CollectionUtils.getPages(insertInput.getRecords(), QueryManager.PAGE_SIZE))
+ String tableName = escapeIdentifier(getTableName(table));
+ StringBuilder sql = new StringBuilder("INSERT INTO ").append(tableName).append("(").append(columns).append(") VALUES");
+ List