mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 05:01:07 +00:00
checkpoint - working version of c3p0 connection pooling, and read-only database meta-data connections (per query hint)
This commit is contained in:
@ -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 //
|
||||
|
@ -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<ReportInput, R
|
||||
queryInput.setTableName(dataSource.getSourceTable());
|
||||
queryInput.setFilter(queryFilter);
|
||||
queryInput.setQueryJoins(dataSource.getQueryJoins());
|
||||
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);
|
||||
|
||||
queryInput.setShouldTranslatePossibleValues(true);
|
||||
queryInput.setFieldsToTranslatePossibleValues(setupFieldsToTranslatePossibleValues(reportInput, dataSource, new JoinsContext(reportInput.getInstance(), dataSource.getSourceTable(), dataSource.getQueryJoins(), queryInput.getFilter())));
|
||||
|
@ -32,13 +32,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import com.kingsrook.qqq.backend.core.actions.QBackendTransaction;
|
||||
import com.kingsrook.qqq.backend.core.actions.customizers.QCodeLoader;
|
||||
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
|
||||
import com.kingsrook.qqq.backend.core.context.QContext;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QValueException;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.insert.InsertInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.QueryHint;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
@ -78,45 +77,6 @@ public class QPossibleValueTranslator
|
||||
|
||||
private int maxSizePerPvsCache = 50_000;
|
||||
|
||||
private Map<String, QBackendTransaction> 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 //
|
||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
@ -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<QueryJoin> queryJoins = null;
|
||||
|
||||
private EnumSet<QueryHint> queryHints = EnumSet.noneOf(QueryHint.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -302,4 +306,78 @@ public class AggregateInput extends AbstractTableActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queryHints
|
||||
*******************************************************************************/
|
||||
public EnumSet<QueryHint> getQueryHints()
|
||||
{
|
||||
return (this.queryHints);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for queryHints
|
||||
*******************************************************************************/
|
||||
public void setQueryHints(EnumSet<QueryHint> queryHints)
|
||||
{
|
||||
this.queryHints = queryHints;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for queryHints
|
||||
*******************************************************************************/
|
||||
public AggregateInput withQueryHints(EnumSet<QueryHint> 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));
|
||||
}
|
||||
}
|
||||
|
@ -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<QueryJoin> queryJoins = null;
|
||||
private Boolean includeDistinctCount = false;
|
||||
|
||||
private EnumSet<QueryHint> queryHints = EnumSet.noneOf(QueryHint.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -207,4 +211,78 @@ public class CountInput extends AbstractTableActionInput
|
||||
return (this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Getter for queryHints
|
||||
*******************************************************************************/
|
||||
public EnumSet<QueryHint> getQueryHints()
|
||||
{
|
||||
return (this.queryHints);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Setter for queryHints
|
||||
*******************************************************************************/
|
||||
public void setQueryHints(EnumSet<QueryHint> queryHints)
|
||||
{
|
||||
this.queryHints = queryHints;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Fluent setter for queryHints
|
||||
*******************************************************************************/
|
||||
public CountInput withQueryHints(EnumSet<QueryHint> 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));
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user