ApTest::DBI - base class for the ATM RDBMS updater libraries
Shane P. McCarron <shane@aptest.com>
Copyright 2001-2009 Applied Testing and Technology, Inc. All Rights Reserved.
The methods in this object provide a base class. Classes that subclass from this will need to provide local methods for several methods in order to have the level of integration they need. Most notably, methods SQL_tname and, if a class requires multiple tables, SQL_tlist must be overridden.
Note that any subclass MUST provide an implementation for SQL_tname. The implementation in this module raises an error and dies.
@list = ApTest::DBI::SQL_available_drivers() ;
Returns a list of the drivers that are installed and supported.
$sql->SQL_begin_work() ;
Starts a SQL transaction. If one is already running, just increases the transaction stack depth. If transactions are not supported by the database engine, silently ignores it.
Returns nothing.
my $available = $sql->SQL_checkTable();
Returns true if the tables needed for the class are available, and false otherwise. Note that all tables returned by SQL_tlist must be available. Also note that if the attribute SQL_MUST_CREATE_TABLES is true, then this method will always return false. Finally, if the attribute SQL_TABLE_EXISTS returns true, then this will return true.
$sql->SQL_commit() ;
Will only actually to the commit if we are at the top of the "begin_work" stack and if transactions are supported.
Returns nothing.
$obj->SQL_queueDelete(table, tid, sid) ;
Queues a delete operation to be executed later via SQL_flushQueue. The delete will remove rows matching (atm_tid, atm_sessionid).
$obj->SQL_queueInsert(table, fields_ref, values_ref) ;
Queues an insert operation to be executed later via SQL_flushQueue.
table is the table name. fields_ref is a reference to an array of field names. values_ref is a reference to an array of values (in same order as fields).
$obj->SQL_clearQueue() ;
Clears all pending queued operations without executing them. Called automatically by SQL_rollback.
$obj->SQL_flushQueue() ;
Executes all queued delete and insert operations in batches. Deletes are executed first, then inserts. Operations are batched in groups of 100 to reduce round trips.
$conn = $self->_SQL_teardownAndReconnect($reason) ;
Internal helper for retry paths. When a query times out (HYT00) or the connection drops (08S01), the old connection may still hold locks in the database server. Simply undef'ing $self->{SQL_DBHANDLE} leaves the old DBI handle alive (referenced by caller-local $conn variables) and the server-side transaction open with its locks held. The new connection then self-deadlocks trying to acquire locks the old connection still owns.
This method:
1. Explicitly rolls back and disconnects the old handle, forcing the
database server to release locks immediately.
2. Undef's C<< $self->{SQL_DBHANDLE} >> so L</SQL_connection> creates
a fresh handle.
3. Calls L</SQL_connection> to establish a new connection.
4. Calls L</SQL_begin_work> on the new connection so the caller's
transaction state is consistent.
Returns the new $conn handle, or undef if reconnection failed.
$rows = $self->_SQL_insertBatch($conn, $table, $field_list,
$row_placeholder, \@batch,
\@fields, $num_fields,
\$deadlock_attempt,
$MAX_DEADLOCK_RETRIES) ;
Internal helper for SQL_flushQueue. Executes the batch INSERT and, on timeout (HYT00) or connection drop (08S01), progressively reduces the batch size and retries:
1. First attempt: full batch (up to 100 rows) 2. Retry 1: reconnect + same batch 3. Retry 2: reconnect + half-size sub-batches 4. Retry 3: reconnect + single-row inserts
This avoids bail-out on large suites where MSSQL contention or Docker resource limits make 100-row INSERTs slow enough to exceed the query timeout.
Returns total rows inserted on success. Returns undef if a deadlock retry was initiated (caller must restart). Dies via SQL_bailOut on non-recoverable errors.
$bool = $obj->SQL_hasQueuedOperations() ;
Returns true if there are pending queued operations.
$cfgHashRef = ApTest::DBI->SQL_config ( suite [,cfhHashRef ] ) ;
$cfhHashRef = $sql->SQL_config( suite [, cfgHashRef ] ) ;
If called outside of an object context, will return the settings. If called in an object context, will cache the settings for the suite within the object in the theory that we will need them again.
suite is the name of the suite we are working with.
cfgHashRef is an optional reference to a populated set of connection configuration information. If provided, this data is updated into the persistent store. The contains the following data items:
Boolean indicating if the SQL connection for the suite is active at all.
The name of a driver to use.
The query portion of the DSN (e.g., host=xxx;port=nnn;database=xyz).
The username to use with the database.
The password to use with the database.
A prefix string to use on tables for this suite. This optional field can be used to prevent collisions among test suites if they are all using the same storage area.
A string to be appended to the create command to do some user-defined special operation.
Boolean indicating if the SQL store is up to date and ready for use. This flag is set to false whenever the connection information is changed or the ApTest Manager field definitions are changed, and is set to true upon completion of a successful synchronize operation. It can also be set to false if a SQL operation fails during the normal course of operations.
A reference to a hash of the various tables created for this test suite. Each table has an entry in the hash. That entry is a reference to a hash of columns and column types. ApTest Manager uses this information to determine if the SQL store's structure matches that of ApTest Manager and is therefor ready for use.
Returns a reference to a hash containing the connection configuration information. If a suite has no defined connection information, returns an empty connection info structure. If the global SQL active param is 1, then returns the global data from config.pl. If it is -1, returns the specific data.
my $dbH = ApTest::DBI::SQL_connect ( suite [, cfg ] ) ;
my $dbH = $sql->SQL_connect( [suite [, cfg ] ] ) ;
suite is an optional suite name. If not provided, the "suite" method of the object will be called.
cfg is a reference to an optional SQL_config hash. If not provided, the stored configuration for the current suite will be used.
Returns a handle to a SQL database for this test suite. Returns undef if there was a problem initializing the connection.
my $dbH = $sql->SQL_connection( [conn, ] );
conn is a handle to an active connection. If provided, this object will take advantage of an existing connection. We will also assume that we are in a connect
Returns a handle to an active SQL connection. Might initiate the connection first.
my $option = $sql->SQL_createOption() ;
Returns a user-defined test suite creation option, or "" if there is no defined option.
my $hashRef = ApTest::DBI::driverMap ;
Returns a reference to a hash mapping known DBD drivers to common names;
my $hashRef = ApTest::DBI::SQL_getInfo($suite) ;
my $hashRef = $sql->SQL_getInfo() ;
$suite is the name of a test suite to check against.
Returns a reference to a hash of interesting setting values for the database associated with test suite $suite, indexed by setting name. The settings retrieved include:
maxTableNameLength
maxColumnsInTable
maxColumnNameLength
my $dbH = $sql->SQL_handle() ;
$dbH = $sql->SQL_handle() ;
$sql->SQL_initialize( );
Returns nothing.
ApTest::DBI::SQL_isActive( suite )
$sql->SQL_isActive( [ suite ] )
suite is the name of the suite to check. It is optional when used in an object context. In an object context, the object's suite method will be used to determine the active suite name.
Returns true if SQL is enabled for the suite.
ApTest::DBI::SQL_isReady( suite )
$sql->SQL_isReady( [ suite ] )
suite is the name of the suite to check. It is optional when used in an object context. In an object context, the object's suite method will be used to determine the active suite name.
Returns true if SQL is enabled AND the underlying SQL store is ready to rock.
$sql->SQL_notifyAdmin(suite, message)
suite is the test suite we are operating on, if any.
message is a message to send. Uses the ATM Notify module to send motification to interested parties.
$sql->SQL_release();
Normally this is called by the enclosing object master release method. If a connection is initiated using some class method, however, then this method can be called and passed the DBI handle.
$sql->SQL_rollback() ;
If we are in a transaction, perform a rollback and clear the transaction stack.
Returns nothing.
$sql->SQL_validateNoOpenTransaction() ;
Validates that there are no open SQL transactions before a fork boundary. This is a critical safety check to prevent data corruption - if a child process inherits an open transaction and attempts to commit or rollback, it can corrupt the parent's transaction state.
Call this method immediately before fork() to ensure fork safety. Will call SQL_bailOut() if an open transaction is detected.
Returns nothing on success.
$sql->SQL_prepareForFork() ;
Prepare database connection for fork by setting InactiveDestroy. Call immediately before fork() to prevent child from closing parent's connection.
When a process forks, the child inherits file descriptors including database connections. If the child closes its copy of the connection (e.g., on exit), it will also close the parent's connection. Setting InactiveDestroy tells DBI not to perform cleanup on this handle when it goes out of scope.
Returns nothing.
my $conn = $sql->SQL_childConnect() ;
Establish fresh SQL connection in forked child process. Call as first action after fork(). Clears inherited handles and connects fresh.
This method: 1. Marks the process as a forked child (IS_FORKED_CHILD flag) 2. Clears inherited handle references (does not close - parent owns them) 3. Removes the DO_NOT_DISCONNECT flag since child owns its new connection 4. Establishes a new connection via SQL_connect()
Returns the new connection handle, or undef on failure.
my $is_child = $sql->SQL_isForkedChild() ;
Returns true if this process is a forked child, false otherwise. This flag is set by SQL_childConnect() or SQL_markAsForkedChild().
$sql->SQL_markAsForkedChild() ;
Mark this process as a forked child. Used by fork management code that needs to set the flag without calling SQL_childConnect().
Returns nothing.
$stH = $sql->SQL_statement( tname )
tname is the name of a table
Returns a handle of a sql insert statement for all columns of table.
$tstamp = $sql->SQL_timestamp( secs [,needTime [,needSecs]] )
secs is seconds since the epoch.
needTime is a boolean for whether to include the time portion or not.
needSecs is a boolean for whether to include the seconds in the time.
Returns a timestamp formatted correctly for the connected RDBMS.
Note that if secs is not defined or is 0, then the time will be initialized to 1970-01-01 00:00:00 UTC, since that is 0 seconds since the epoch.
@tlist = $sql->tlist();
Returns a list of table names related to the current object. This default implementation ONLY returns the base table name.
my $name = $sql->SQL_tname() ;
Note that this method MUST be overridden in a sub-class.
$len = $sql->SQL_tname_maxlen();
Returns the maximum table name length for the underlying SQL driver.
$value = $sql->SQL_truncate(tName, fName, value)
Name of the table we are operating on.
Name of the field in the table.
The value that might need truncation.
Note that fields are ONLY truncated in cases where there is a problem with the underlying SQL store of when the data in ApTest Manager somehow exceeds its limits.
$btype = $sql->SQL_basetype(SQL_TYPE) ;
$sql->SQL_bailOut(message) ;
message is message text that will be put into the log AND reported to the end user. The log will also have a Carp::longmess entry so the entire stack trace is available.
$sqltype = $sql->SQL_type(basetype [, maxlen])
basetype is an ATM base type. This is one of UUID, DATE, DATETIME, INTEGER, NUMBER, and TEXT.
maxlen is the optional maximum length of the content. If it is not specified, and the resulting type takes a max length creation parameter, then the field maximum will be used by default.
Note that for a given basetype, we will only look up the supported underlying type from the driver once - after which we will cache its name and its number.
my $ver = $sql->SQL_version( [suite] ) ;
suite is an optional suite name.
Returns a string representing the version.
Copyright © 2000-2013 Applied Testing and Technology, Inc. All rights reserved.