Class AbstractRDBMSAction
java.lang.Object
com.kingsrook.qqq.backend.module.rdbms.actions.AbstractRDBMSAction
- Direct Known Subclasses:
RDBMSAggregateAction,RDBMSCountAction,RDBMSDeleteAction,RDBMSInsertAction,RDBMSQueryAction,RDBMSUpdateAction
Base class for all core actions in the RDBMS module.
Provides common functionality for query construction, SQL generation, result
set processing, and connection management across all RDBMS backend operations.
Handles database-agnostic SQL building with vendor-specific strategies,
security lock application, join processing, and filter criteria translation.
Key responsibilities:
- SQL clause generation (SELECT, FROM, WHERE, ORDER BY)
- PreparedStatement parameter management
- Join context resolution and FROM clause construction
- Security criteria integration via RecordSecurityLocks
- Result set field extraction with type conversion
- Database connection acquisition from ConnectionManager
- Query cancellation support for long-running operations
All concrete RDBMS action implementations (Query, Count, Insert, Update, Delete)
extend this class to leverage shared SQL building and data access patterns.
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected booleanprotected QueryStatprotected PreparedStatement -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionprotected QQueryFilterclonedOrNewFilter(QQueryFilter filter) Either clone the input filter (so we can change it safely), or return a new blank filter.protected voidCancel an in-progress SQL query.protected booleanDetermine if a SELECT clause requires DISTINCT due to security lock joins.protected StringEscape an identifier (table name, column name) with the appropriate quote character for the database vendor.protected RDBMSActionStrategyInterfaceGetter for the action strategy.static StringgetColumnName(QFieldMetaData field) Get the column name to use for a field in the RDBMS, from the fieldMetaData.static ConnectiongetConnection(AbstractTableActionInput tableActionInput) Get a database connection, per the backend in the request.protected SerializablegetFieldValueFromResultSet(QFieldMetaData qFieldMetaData, ResultSet resultSet, int i) Extract a field value from a ResultSet using field metadata.protected SerializablegetFieldValueFromResultSet(QFieldType type, ResultSet resultSet, int i) Extract a field value from a ResultSet using the action strategy.Getter for queryStat.protected StringgetSingleGroupByClause(GroupBy groupBy, JoinsContext joinsContext) Build a single GROUP BY clause element with optional formatting.static StringgetTableName(QTableMetaData table) Get the table name to use in the RDBMS from a QTableMetaData.protected voidlogSQL(CharSequence sql, List<?> params, Long mark) Log SQL statements and parameters when debug logging is enabled.protected StringmakeFromClause(QInstance instance, String tableName, JoinsContext joinsContext, List<Serializable> params) Build the FROM clause for a SQL query, including all JOIN clauses.protected StringmakeOrderByClause(QTableMetaData table, List<QFilterOrderBy> orderBys, JoinsContext joinsContext) Build the ORDER BY clause for a SQL query.protected StringmakeWhereClause(JoinsContext joinsContext, QQueryFilter filter, List<Serializable> params) Method to make a full WHERE clause.protected SerializablescrubValue(QFieldMetaData field, Serializable value) Handle obvious problems with values - like empty string for integer should be null, and type conversions that we can do "better" than jdbc.protected voidsetBackendMetaData(QBackendMetaData backendMetaData) Setter for backendMetaData.static voidsetLogSQL(boolean on) Make it easy (e.g., for tests) to turn on logging of SQLstatic voidMake it easy (e.g., for tests) to turn on logging of SQLstatic voidsetLogSQLOutput(String loggerOrSystemOut) Make it easy (e.g., for tests) to turn on logging of SQLstatic voidsetLogSQLReformat(boolean doReformat) Make it easy (e.g., for tests) to turn on poor-man's formatting of SQLvoidsetQueryStat(QueryStat queryStat) Setter for queryStat.protected voidsetSqlAndJoinsInQueryStat(CharSequence sql, JoinsContext joinsContext) Record SQL query text and join table names in the QueryStat for metrics.protected voidsetValueIfTableHasField(QRecord record, QTableMetaData table, String fieldName, Serializable value) If the table has a field with the given name, then set the given value in the given record.
-
Field Details
-
queryStat
-
statement
-
isCancelled
protected boolean isCancelled
-
-
Constructor Details
-
AbstractRDBMSAction
public AbstractRDBMSAction()
-
-
Method Details
-
getTableName
Get the table name to use in the RDBMS from a QTableMetaData. That is, table.backendDetails.tableName if set -- else, table.name -
getColumnName
Get the column name to use for a field in the RDBMS, from the fieldMetaData. That is, field.backendName if set -- else, field.name -
getConnection
public static Connection getConnection(AbstractTableActionInput tableActionInput) throws SQLException 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.- Throws:
SQLException
-
setLogSQL
Make it easy (e.g., for tests) to turn on logging of SQL -
setLogSQL
public static void setLogSQL(boolean on) Make it easy (e.g., for tests) to turn on logging of SQL -
setLogSQLOutput
Make it easy (e.g., for tests) to turn on logging of SQL -
setLogSQLReformat
public static void setLogSQLReformat(boolean doReformat) Make it easy (e.g., for tests) to turn on poor-man's formatting of SQL -
scrubValue
Handle obvious problems with values - like empty string for integer should be null, and type conversions that we can do "better" than jdbc. Performs type coercion and normalization of values before they are set in PreparedStatements. Converts empty strings to null for typed fields, and uses ValueUtils for string-to-type conversions that are more forgiving than JDBC's default behavior.- Parameters:
field- the field metadata defining expected typevalue- the raw value to scrub/convert- Returns:
- the scrubbed value, properly typed or null
-
setValueIfTableHasField
protected void setValueIfTableHasField(QRecord record, QTableMetaData table, String fieldName, Serializable value) If the table has a field with the given name, then set the given value in the given record. Safely attempts to set a field value, gracefully handling the case where the field does not exist in the table metadata. Used when populating records from result sets where columns may not map to all defined fields.- Parameters:
record- the record to populatetable- the table metadata to check for field existencefieldName- the name of the field to setvalue- the value to set in the field
-
makeFromClause
protected String makeFromClause(QInstance instance, String tableName, JoinsContext joinsContext, List<Serializable> params) Build the FROM clause for a SQL query, including all JOIN clauses. Constructs the full FROM clause starting with the main table, then adds all joins from the JoinsContext in proper order. Handles table aliasing, join type specification (INNER, LEFT, etc.), and ON clause generation from join metadata. Also integrates security criteria into join ON clauses where applicable.- Parameters:
instance- the QInstance containing table and join metadatatableName- the name of the main tablejoinsContext- context containing all joins to include in the queryparams- list to populate with parameter values from security criteria- Returns:
- the complete FROM clause including all joins
-
makeWhereClause
protected String makeWhereClause(JoinsContext joinsContext, QQueryFilter filter, List<Serializable> params) throws IllegalArgumentException Method to make a full WHERE clause. Note that criteria for security are assumed to have been added to the filter during the construction of the JoinsContext.- Throws:
IllegalArgumentException
-
escapeIdentifier
Escape an identifier (table name, column name) with the appropriate quote character for the database vendor. Uses the action strategy's getIdentifierQuoteString() method to determine the appropriate quote character. Falls back to backtick if strategy not available. -
getFieldValueFromResultSet
protected Serializable getFieldValueFromResultSet(QFieldType type, ResultSet resultSet, int i) throws SQLException Extract a field value from a ResultSet using the action strategy. Delegates to the configured RDBMSActionStrategyInterface to handle vendor- specific type mappings and conversions when reading values from result sets.- Parameters:
type- the QQQ field type to extractresultSet- the JDBC ResultSet to read fromi- the 1-based column index in the result set- Returns:
- the extracted value as a Serializable
- Throws:
SQLException- if the value cannot be read from the result set
-
getFieldValueFromResultSet
protected Serializable getFieldValueFromResultSet(QFieldMetaData qFieldMetaData, ResultSet resultSet, int i) throws SQLException Extract a field value from a ResultSet using field metadata. Convenience method that extracts the type from field metadata and delegates to the type-based extraction method.- Parameters:
qFieldMetaData- the field metadata containing the type informationresultSet- the JDBC ResultSet to read fromi- the 1-based column index in the result set- Returns:
- the extracted value as a Serializable
- Throws:
SQLException- if the value cannot be read from the result set
-
makeOrderByClause
protected String makeOrderByClause(QTableMetaData table, List<QFilterOrderBy> orderBys, JoinsContext joinsContext) Build the ORDER BY clause for a SQL query. Constructs ORDER BY clause from a list of QFilterOrderBy specifications. Handles regular field ordering, aggregate function ordering, and group-by ordering. Resolves field names through the joins context to ensure proper table aliasing. Applies ASC/DESC direction per each order-by specification.- Parameters:
table- the main table metadata (used for aggregate field resolution)orderBys- list of order-by specifications to convert to SQLjoinsContext- context for resolving field names to table aliases- Returns:
- comma-separated ORDER BY clause string
-
getSingleGroupByClause
Build a single GROUP BY clause element with optional formatting. Constructs a GROUP BY clause for a single field, resolving the field name through the joins context and applying any format string (e.g., for date truncation functions like DATE_TRUNC).- Parameters:
groupBy- the group-by specification containing field name and optional formatjoinsContext- context for resolving field names to table aliases- Returns:
- the GROUP BY clause element (e.g., "table.field" or "DATE(table.field)")
-
logSQL
Log SQL statements and parameters when debug logging is enabled. Conditionally logs SQL statements, parameter values, and execution timing based on system properties (qqq.rdbms.logSQL, qqq.rdbms.logSQL.output, qqq.rdbms.logSQL.reformat). Supports both logger-based output and System.out for test scenarios. Applies basic formatting to improve SQL readability when reformat flag is enabled.- Parameters:
sql- the SQL statement to logparams- list of parameter values (limited to first 100 for performance)mark- timestamp for calculating execution duration, or null if not tracking
-
doesSelectClauseRequireDistinct
Determine if a SELECT clause requires DISTINCT due to security lock joins. Analyzes the table's RecordSecurityLocks to detect one-to-many joins where the base table is on the "left" side. Such joins can produce duplicate rows that must be eliminated with SELECT DISTINCT. Memoized because the analysis is complex and the result never changes for a given table during server runtime. Cache expires after 365 days.- Parameters:
table- the table metadata to analyze for DISTINCT requirement- Returns:
- true if SELECT DISTINCT is required, false otherwise
-
setSqlAndJoinsInQueryStat
Record SQL query text and join table names in the QueryStat for metrics. Updates the QueryStat (if present) with the generated SQL text and the set of table names involved in joins. Used for query performance tracking, logging, and analytics.- Parameters:
sql- the generated SQL query text to recordjoinsContext- context containing join information, or null if no joins
-
getQueryStat
Getter for queryStat.- Returns:
- the current QueryStat instance used for performance tracking
-
setQueryStat
Setter for queryStat.- Parameters:
queryStat- the QueryStat instance to use for performance tracking
-
doCancelQuery
protected void doCancelQuery()Cancel an in-progress SQL query. Sets the cancellation flag and attempts to cancel the current PreparedStatement. Used to support user-initiated query cancellation or timeout enforcement for long-running operations. Gracefully handles cases where no statement is active. -
clonedOrNewFilter
Either clone the input filter (so we can change it safely), or return a new blank filter. Ensures immutability of input filters by creating a deep copy before applying security criteria or other modifications. Returns new empty filter if input is null.- Parameters:
filter- the filter to clone, or null- Returns:
- cloned filter if input was non-null, otherwise a new empty filter
-
setBackendMetaData
Setter for backendMetaData. Initializes the backend metadata and associated action strategy. The action strategy provides database vendor-specific SQL generation and type handling.- Parameters:
backendMetaData- the backend metadata (must be RDBMSBackendMetaData)
-
getActionStrategy
Getter for the action strategy. Returns the database vendor-specific strategy implementation used for SQL generation, type conversions, and dialect-specific behavior.- Returns:
- the configured RDBMSActionStrategyInterface instance
-