Class AbstractRDBMSAction

java.lang.Object
com.kingsrook.qqq.backend.module.rdbms.actions.AbstractRDBMSAction
Direct Known Subclasses:
RDBMSAggregateAction, RDBMSCountAction, RDBMSDeleteAction, RDBMSInsertAction, RDBMSQueryAction, RDBMSUpdateAction

public abstract class AbstractRDBMSAction extends Object
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 Details

    • queryStat

      protected QueryStat queryStat
    • statement

      protected PreparedStatement statement
    • isCancelled

      protected boolean isCancelled
  • Constructor Details

    • AbstractRDBMSAction

      public AbstractRDBMSAction()
  • Method Details

    • getTableName

      public static String getTableName(QTableMetaData table)
      Get the table name to use in the RDBMS from a QTableMetaData. That is, table.backendDetails.tableName if set -- else, table.name
    • getColumnName

      public static String getColumnName(QFieldMetaData field)
      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

      public static void setLogSQL(boolean on, boolean doReformat, String loggerOrSystemOut)
      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

      public static void setLogSQLOutput(String loggerOrSystemOut)
      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

      protected Serializable scrubValue(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. 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 type
      value - 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 populate
      table - the table metadata to check for field existence
      fieldName - the name of the field to set
      value - 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 metadata
      tableName - the name of the main table
      joinsContext - context containing all joins to include in the query
      params - 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

      protected String escapeIdentifier(String id)
      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 extract
      resultSet - the JDBC ResultSet to read from
      i - 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 information
      resultSet - the JDBC ResultSet to read from
      i - 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 SQL
      joinsContext - context for resolving field names to table aliases
      Returns:
      comma-separated ORDER BY clause string
    • getSingleGroupByClause

      protected String getSingleGroupByClause(GroupBy groupBy, JoinsContext joinsContext)
      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 format
      joinsContext - context for resolving field names to table aliases
      Returns:
      the GROUP BY clause element (e.g., "table.field" or "DATE(table.field)")
    • logSQL

      protected void logSQL(CharSequence sql, List<?> params, Long mark)
      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 log
      params - list of parameter values (limited to first 100 for performance)
      mark - timestamp for calculating execution duration, or null if not tracking
    • doesSelectClauseRequireDistinct

      protected boolean doesSelectClauseRequireDistinct(QTableMetaData table)
      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

      protected void setSqlAndJoinsInQueryStat(CharSequence sql, JoinsContext joinsContext)
      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 record
      joinsContext - context containing join information, or null if no joins
    • getQueryStat

      public QueryStat getQueryStat()
      Getter for queryStat.
      Returns:
      the current QueryStat instance used for performance tracking
    • setQueryStat

      public void setQueryStat(QueryStat queryStat)
      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

      protected QQueryFilter clonedOrNewFilter(QQueryFilter filter)
      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

      protected void setBackendMetaData(QBackendMetaData backendMetaData)
      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

      protected RDBMSActionStrategyInterface 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