The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Class::ReluctantORM::Driver - Abstract interface for RDBMSs

SYNOPSIS

  # ---- Driver Creation ----
  # Driver instantiation is usually implicit
  MyClass->build_class($dbh => $some_database_handle);
  $driver = MyClass->driver();

  # To do it explicitly...
  # Create a raw database connection (or use a Class::ReluctantORM::DBH subclass)
  my $dbh = DBI->connect(...);

  # Now make a driver from the handle.  The $dbh will
  # be checked for its RDBMS brand and version, and the
  # best-matching Driver subclass will be used.
  my $driver = Class::ReluctantORM::Driver->make_driver($cro_class, $dbh);

  # ---- SQL Parsing ----
  if ($driver->supports_parsing()) {
    $sql_obj = $driver->parse_statement("SELECT foo FROM bar WHERE baz = 'beep'");
    $sql_where = $driver->parse_where("baz = 'beep'");
    $sql_order_by = $driver->parse_order_by("dog DESC");
  }

  # ---- SQL Rendering ----
  $sql_string = $driver->render($sql_obj, $hints);

  # ---- SQL Execution ----
  $driver->run_sql($sql_obj);

  # If you like prepare-execute cycles...
  $driver->prepare($sql_obj);
  if ($sql_obj->is_prepared()) {
      $sql_obj->execute(@bindings);  # Use output columns or callback to fetch results
      $sql_obj->finish();
  }

  # Or just get the DBI dbh and bang on it directly
  my $dbi_dbh = $driver->dbi_dbh();
  # (normally in autocommit mode)
  if ($driver->supports_transactions()) {
     $driver->begin_transaction();

     # Do things....

     if ($driver->is_in_transaction()) { ... }

     if (...) {
        $driver->commit_transaction();
     } else {
        $driver->rollback_transaction();
     }
     # Returns to autocommit after a call to either commit or rollback

  }
  # ---- DB MetaData and SQL String Utils ----
  $field2column_map = $driver->read_fields($schema, $table);     # May be cached
  @columns = $driver->find_primary_key_columns($schema, $table); # May be cached
  $char = $driver->open_quote();
  $char = $driver->close_quote();
  $char = $driver->name_separator();
  $str = $driver->table_case($name);
  $str = $driver->schema_case($name);
  $str = $driver->column_case($name);

DESCRIPTION

The Driver facility provides RDBMS-specific dialect support. In other words, high-level methods (like reading a list of fields in a table) are available via any Driver, while behind the scenes a Driver subclass is speaking a particular dialect to your database handle.

Drivers provide five major groups of functionality:

Database metadata access

List columns, keys, etc. This area is immature.

SQL Generation

Transform a CRO SQL object into a SQL string in the driver's dialect. See render()

SQL Execution

Using the Class::ReluctantORM::DBH, execute SQL strings on the database and retrieve the results. See prepare()

SQL Parsing

Transform a SQL string in the Driver's dialect into a CRO SQL object for later manipulation. Such support is just out of its infancy - call it toddler-dom. See supports_parsing(), parse_statement(), and parse_where().

Monitor Support

Drivers are the internal attachment point for Monitors, which are used to track database access.

This page documents the Driver superclass, which specifies the API provided by all drivers. See the individual drivers to learn more about their idiosyncracies (eg Class::ReluctantORM::Driver::PostgreSQL).

Each Class::ReluctantORM subclass has its own Driver (this allows different classes to originate from different databases). It is expected that you will re-use database handles across multiple drivers, however.

METHODS TO OVERRIDE WHEN SUBCLASSING

When creating an RDBMS-specific subclass, you will need to override the following methods:

aptitude
init
read_fields
find_primary_key_columns
run_sql
execute_fetch_deep
render
prepare
supports_parsing
parse_statement
parse_where
parse_order_by

INSTANCE METHODS

$dbh = $driver->cro_dbh();

Returns the Class::ReluctantORM::DBH object that provides low-level connectivity.

$dbh = $driver->dbi_dbh();

Returns a DBI database handle. If the Class::ReluctantORM::DBH object is not based on DBI, this will be undef.

$bool = $driver->supports_namespaces()

Returns true if the driver supports namespaces (schemae - containers within a database for tables). If so, you can use name_separator to construct fully qualified table names.

Default implementation returns false.

DRIVER SETUP METHODS

$driver = Class::ReluctantORM::Driver->make_driver($cro_class, $dbhandle, $dbclass);

Searches for the best available driver for the given database handle. The Class::ReluctantORM subclass name is passed for advisory purposes to the underlying driver subclass.

$n = $class->aptitude($brand, $version);

Should return a number between 0 and 1 indicating how well the driver can handle the given type of database server. Scores less than 0.5 are considered ill-equipped. The highest-scoring driver will be used.

Default implementation returns 0.

$driver->init();

Called with no args just after driver construction. The dbh is available at this point.

Default implementation does nothing.

DATABASE METADATA METHODS

$version_string = $driver->server_brand();

Returns the vendor-specific brand name (cached from Driver creation, the result of a DBI get_info SQL_DBMS_NAME call).

$version_string = $driver->server_version();

Returns the vendor-specific version string (cached from Driver creation, the result of a DBI get_info SQL_DBMS_VER call).

$field2column_map = $driver->read_fields($schema_name, $table_name);

Scans the associated table for columns, and returns a hash mapping lowercased field named to database case column names.

This data may be cached. See the Class::ReluctantORM global option schema_cache_policy, and the Class::ReluctantORM::SchemaCache .

Default implementation throws a PureVirtual exception. You must override this method.

@cols = $driver->find_primary_key_columns();

Returns a list of columns used in the table's primary key. This is usually a one-item list.

This data may be cached. See the Class::ReluctantORM global option schema_cache_policy, and Class::ReluctantORM::SchemaCache .

Default implementation throws a PureVirtual exception. You must override this method.

$str = $driver->schema_case($str);

$str = $driver->table_case($str);

$str = $driver->column_case($str);

Adjusts the given string to be in the case expected by the driver for the given object type.

Default implementation is to lowercase everything.

SQL EXECUTION SUPPORT

These methods provide the rendering and execution capabilities of the driver.

Execution Hinting

Most of the execution support methods accept an optional hashref that provides hints for the driver. Currently supported hints:

already_transformed

Boolean, default false. If true, indicates that the given SQL object has already been through its transformation phase, and should not be trnasformed again.

Specific drivers may extend this list.

$driver->run_sql($sql, $hints);

Executes the given SQL object. The SQL object then contains the results; you can also use the $sql->add_fetchrow_listener() method to add a hook.

The 'hints' arg is optional, and is a hashref as specified in EXECUTION HINTING.

A reasonable default implementation is provided.

@results = $driver->execute_fetch_deep($sql_obj);

Renders, executes, and parses the results of a "fetch deep" style SQL query. Internally, this may be the same as run_sql; but some drivers may need to perform extra transformations for fetch deep (to allow use of LIMIT clauses, for example).

$str = $driver->render($sql_obj, $hints);

Takes a Class::ReluctantORM::SQL object, and renders it down to a SQL string.

The 'hints' arg is optional, and is a hashref as specified in EXECUTION HINTING.

$sth = $driver->prepare($sql_obj, $hints);

Renders the SQL object to a SQL string, then passes it through the underlying DBI dbh, and returns the resulting statement handle. You can then use either $sql_obj->execute() or if you prefer a lower-level approach, you can operate directly on the statement handle.

The 'hints' arg is optional, and is a hashref as specified in EXECUTION HINTING.

A reasonable default implementation is provided.

$bool = $driver->supports_parsing();

Returns true if you can call parse_statement() or parse_where() and expect it to possibly work.

Default implementation returns false.

$sql_obj = $driver->parse_statement($sql_string, $options);

EXERIMENTAL

Examines the $sql_string, and builds a Class::ReluctantORM::SQL object that semantically represents the statement. Syntax details will not be preserved - you can't round-trip this.

If a problem occurs, an exception will be thrown, either Class::ReluctantORM::Exception::SQL::ParseError (your fault for sending garbage) or Class::ReluctantORM::Exception::SQL::TooComplex (our fault for having a weaksauce parser).

$options is an optional hashref that contains parsing options or hints for the parser. It may be dialect specific - see your driver subclass for details.

$where_obj = $driver->parse_where($where_clause_string, $options);

EXERIMENTAL

Examines the $where_clause_string, and builds a Class::ReluctantORM::SQL::Where object that semantically represents the WHERE clause. You should not include the word WHERE.

Other details as for parse_statement.

$order_by_obj = $driver->parse_order_by($order_clause_string, $options);

EXERIMENTAL

Examines the $order_clause_string, and builds a Class::ReluctantORM::SQL::OrderBy object that semantically represents the clause. You should not include the words ORDER BY.

Other details as for parse_statement.

A default implementation is provided. It's stupid - it only allows column names and sort directions, no expressions.