SQLAlchemy 0.5 Documentation - module sqlalchemy.databases.firebird

# SQLAlchemy 0.5 Documentation

Multiple Pages | One Page
Version: 0.5.0beta2 Last Updated: 07/14/08 16:12:25

### module sqlalchemy.databases.firebird

This module implements the Firebird backend, thru the kinterbasdb DBAPI module.

# Firebird dialects

Firebird offers two distinct dialects (not to be confused with the SA `Dialect` thing):

dialect 1
  This is the old syntax and behaviour, inherited from Interbase pre-6.0.
dialect 3
  This is the newer and supported syntax, introduced in Interbase 6.0.

From the user point of view, the biggest change is in date/time handling: under dialect 1, there's a single kind of field, `DATE` with a synonim `DATETIME`, that holds a timestamp value, that is a date with hour, minute, second. Under dialect 3 there are three kinds, a `DATE` that holds a date, a `TIME` that holds a time of the day value and a `TIMESTAMP`, equivalent to the old `DATE`.

The problem is that the dialect of a Firebird database is a property of the database itself [1] (that is, any single database has been created with one dialect or the other: there is no way to change the after creation). SQLAlchemy has a single instance of the class that controls all the connections to a particular kind of database, so it cannot easily differentiate between the two modes, and in particular it cannot simultaneously talk with two distinct Firebird databases with different dialects.

By default this module is biased toward dialect 3, but you can easily tweak it to handle dialect 1 if needed:

    from sqlalchemy import types as sqltypes
    from sqlalchemy.databases.firebird import FBDate, colspecs, ischema_names

    # Adjust the mapping of the timestamp kind
    ischema_names['TIMESTAMP'] = FBDate
    colspecs[sqltypes.DateTime] = FBDate,

Other aspects may be version-specific. You can use the `server_version_info()` method on the `FBDialect` class to do whatever is needed:

    from sqlalchemy.databases.firebird import FBCompiler

    if engine.dialect.server_version_info(connection) < (2,0):
        # Change the name of the function ``length`` to use the UDF version
        # instead of ``char_length``
        FBCompiler.LENGTH_FUNCTION_NAME = 'strlen'

# Pooling connections

The default strategy used by SQLAlchemy to pool the database connections in particular cases may raise an `OperationalError` with a message "object XYZ is in use". This happens on Firebird when there are two connections to the database, one is using, or has used, a particular table and the other tries to drop or alter the same table. To garantee DDL operations success Firebird recommend doing them as the single connected user.

In case your SA application effectively needs to do DDL operations while other connections are active, the following setting may alleviate the problem:

    from sqlalchemy import pool
    from sqlalchemy.databases.firebird import dialect

    # Force SA to use a single connection per thread
    dialect.poolclass = pool.SingletonThreadPool

# RETURNING support

Firebird 2.0 supports returning a result set from inserts, and 2.1 extends that to deletes and updates.

To use this pass the column/expression list to the `firebird_returning` parameter when creating the queries:

    raises = tbl.update(empl.c.sales > 100, values=dict(salary=empl.c.salary * 1.1),
                        firebird_returning=[empl.c.id, empl.c.salary]).execute().fetchall()

[1] | Well, that is not the whole story, as the client may still ask a different (lower) dialect...

### class FBBinary(Binary)

Handle `BLOB SUB_TYPE 0` datatype (aka binary blob).

def get_col_spec(self)
back to section top

### class FBBoolean(Boolean)

Handle boolean values as a `SMALLINT` datatype.

def get_col_spec(self)
back to section top

### class FBChar(CHAR)

Handle `CHAR(length)` datatype.

def get_col_spec(self)
back to section top

### class FBCompiler(DefaultCompiler)

Firebird specific idiosincrasies

def default_from(self)
def function_argspec(self, func)
def function_string(self, func)

Substitute the `length` function.

On newer FB there is a `char_length` function, while older ones need the `strlen` UDF.

def get_select_precolumns(self, select)

Called when building a `SELECT` statement, position is just before column list Firebird puts the limit and offset right after the `SELECT`...

def limit_clause(self, select)

Already taken care of in the get_select_precolumns method.

def visit_alias(self, alias, asfrom=False, **kwargs)
def visit_delete(self, delete_stmt)
def visit_insert(self, insert_stmt)
def visit_sequence(self, seq)
def visit_update(self, update_stmt)
back to section top

### class FBDate(DateTime)

Handle `DATE` datatype.

def get_col_spec(self)
back to section top

### class FBDateTime(DateTime)

Handle `TIMESTAMP` datatype.

def bind_processor(self, dialect)
def get_col_spec(self)
back to section top

### class FBDefaultRunner(DefaultRunner)

Firebird specific idiosincrasies

def visit_sequence(self, seq)

Get the next value from the sequence using `gen_id()`.

back to section top

### class FBDialect(DefaultDialect)

Firebird dialect

def __init__(self, type_conv=200, concurrency_level=1, **kwargs)

Construct a new `FBDialect`.

def create_connect_args(self, url)
def create_execution_context(self, *args, **kwargs)
def dbapi(cls)
def do_commit(self, connection)
def do_execute(self, cursor, statement, parameters, **kwargs)
def do_rollback(self, connection)
def has_sequence(self, connection, sequence_name)

Return `True` if the given sequence (generator) exists.

def has_table(self, connection, table_name, schema=None)

Return `True` if the given table exists, ignoring the schema.

def is_disconnect(self, e)
def reflecttable(self, connection, table, include_columns)
def server_version_info(self, connection)

Get the version of the Firebird server used by a connection.

Returns a tuple of (major, minor, build), three integers representing the version of the attached server.

def table_names(self, connection, schema)

Return a list of normalized table names omitting system relations.

def type_descriptor(self, typeobj)
back to section top

### class FBExecutionContext(DefaultExecutionContext)

def returns_rows_compiled(self, compiled)
def returns_rows_text(self, statement)
back to section top

### class FBFloat(Float)

Handle `FLOAT(precision)` datatype.

def get_col_spec(self)
back to section top

### class FBIdentifierPreparer(IdentifierPreparer)

Install Firebird specific reserved words.

def __init__(self, dialect)

Construct a new `FBIdentifierPreparer`.

back to section top

### class FBInteger(Integer)

Handle `INTEGER` datatype.

def get_col_spec(self)
back to section top

### class FBNumeric(Numeric)

Handle `NUMERIC(precision,length)` datatype.

def bind_processor(self, dialect)
def get_col_spec(self)
def result_processor(self, dialect)
back to section top

### class FBSchemaDropper(SchemaDropper)

Firebird syntactic idiosincrasies

def visit_sequence(self, sequence)

Generate a `DROP GENERATOR` statement for the sequence.

back to section top

### class FBSchemaGenerator(SchemaGenerator)

Firebird syntactic idiosincrasies

def get_column_specification(self, column, **kwargs)
def visit_sequence(self, sequence)

Generate a `CREATE GENERATOR` statement for the sequence.

back to section top

### class FBSmallInteger(SmallInteger)

Handle `SMALLINT` datatype.

def get_col_spec(self)
back to section top

### class FBString(String)

Handle `VARCHAR(length)` datatype.

def get_col_spec(self)
back to section top

### class FBText(Text)

Handle `BLOB SUB_TYPE 1` datatype (aka textual blob).

def get_col_spec(self)
back to section top

### class FBTime(Time)

Handle `TIME` datatype.

def get_col_spec(self)
back to section top