All pastes #940163 Raw Edit

Someone

public text v1 · immutable
·published 2008-03-12 20:19 UTC
rendered paste body
#-*- coding: ISO-8859-1 -*-
# sqlite3/_sqlite3.py: the jythonsqlite package.
#
# Copyright (C) 2007 Michael Dubner <dubnerm@mindless.com>
#
# This file is part of jythonsqlite.
#
# This software is provided 'as-is', without any express or implied
# warranty.  In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
#    claim that you wrote the original software. If you use this software
#    in a product, an acknowledgment in the product documentation would be
#    appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
#    misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.

import re as _re
import thread as _thread
from weakref import ref as _ref
#from SQLite import Vm as Statement #it is broken for some reason
from SQLite import Database as _Database
from SQLite import Trace as _Trace
from SQLite import Callback as _Callback
from SQLite import Authorizer as _Authorizer
from SQLite import Function as _Function
from SQLite import Exception as _Exception
from SQLite.Constants import *

version = "1.0"
sqlite_version = _Database.version()

DEFAULT_TIMEOUT = 5.0
PARSE_DECLTYPES = 1
PARSE_COLNAMES = 2

if SQLITE_DETACH == 25:
  SQLITE_ALTER_TABLE = 26
  SQLITE_REINDEX = 27
  SQLITE_ANALYZE = 28

STATEMENT_INVALID = 0
STATEMENT_INSERT = 1
STATEMENT_DELETE = 2
STATEMENT_UPDATE = 3
STATEMENT_REPLACE = 4
STATEMENT_SELECT = 5
STATEMENT_OTHER = 6

class Error(StandardError): pass
class Warning(StandardError): pass
class InterfaceError(Error): pass
class DatabaseError(Error): pass
class InternalError(DatabaseError): pass
class OperationalError(DatabaseError): pass
class ProgrammingError(DatabaseError): pass
class IntegrityError(DatabaseError): pass
class DataError(DatabaseError): pass
class NotSupportedError(DatabaseError): pass

class PrepareProtocol(object): pass

_enable_callback_tracebacks = 0
converters = {}
adapters = {}


class Connection(object):
  """SQLite database connection object."""
  class _TraceDebug(_Trace):
    def trace(self, stmt):
      print '+', stmt
  _trace_debug = _TraceDebug()

  class _UserFunction(_Function):
    def __init__(self, connection, func):
      self.func = func
      self.connection = connection
      self.agg = {}
    def function(self, fc, args):
      args = [_cast_value(val, None, self.connection.text_factory) for val in args]
      try:
        res = self.func(*args)
      except Exception, err:
        #fc.set_error("user-defined function raised exception")
        raise OperationalError, "user-defined function raised exception"
      res = _prepare_args([res])[0]
      if res is not None:
        fc.set_result(res)
    def step(self, fc, args):
      agg = self.agg.get(id(fc))
      if agg is None:
        try:
          agg = self.func()
        except Exception, err:
          #fc.set_error("user-defined function raised exception")
          raise OperationalError, "user-defined function raised exception"
        self.agg[id(fc)] = agg
      args = [_cast_value(val, None, self.connection.text_factory) for val in args]
      try:
        agg.step(*args)
      except Exception, err:
        #fc.set_error("user-defined function raised exception")
        raise OperationalError, "user-defined function raised exception"
    def last_step(self, fc):
      agg = self.agg[id(fc)]
      try:
        res = agg.finalize(*args)
      except Exception, err:
        #fc.set_error("user-defined function raised exception")
        raise OperationalError, "user-defined function raised exception"
      res = _prepare_args([res])[0]
      if res is not None:
        fc.set_result(res)
      
  class _UserAuthorizer(_Authorizer):
    def __init__(self, connection, func):
      self.func = func
      self.connection = connection
    def authorize(self, action, arg1, arg2, dbname, source):
      try:
        return self.func(action, arg1, arg2, dbname, source)
        #if self.func(action, arg1, arg2, dbname, source) == SQLITE_DENY:
        #  raise DatabaseError, "prohibited"
      except Exception, err:
        raise OperationalError, "user-defined function raised exception"

  def __init__(self, database=":memory:", timeout=DEFAULT_TIMEOUT, detect_types=0,
                     isolation_level="", check_same_thread=1, cached_statements=100):
    self.row_factory = None
    self.text_factory = unicode
    self._isolation_level = None
    self._begin_statement = None
    self._statement_cache = None
    self._statements = None
    self._timeout = timeout
    self._detect_types = detect_types
    try:
      self.db = _Database()
      self.db.open(database, 0666)
      self.db.set_encoding('utf-8')
      self.db.busy_timeout(int(self._timeout*1000))
      self.db.exec('pragma show_datatypes', None)
      #self.db.trace(self._trace_debug)
    except _Exception, err:
      raise OperationalError, err
    err = self.db.last_error()
    if err: raise DatabaseError, "self.db.last_error() = "+str(err)
    self.isolation_level = isolation_level
    self._statement_cache = Cache(self, cached_statements)
    self._cursors = []
    self._inTransaction = 0
    self._user_functions = {}
    self._thread_ident = _thread.get_ident()
    self._check_same_thread = check_same_thread
    self._function_pinboard = {}
    self._collations = {}
    self._total_changes = 0
    #for strict compatibility
    self.Warning = Warning
    self.Error = Error
    self.InterfaceError = InterfaceError
    self.DatabaseError = DatabaseError
    self.DataError = DataError
    self.OperationalError = OperationalError
    self.IntegrityError = IntegrityError
    self.InternalError = InternalError
    self.ProgrammingError = ProgrammingError
    self.NotSupportedError = NotSupportedError

  def _flush_statement_cache(self):
    self._statement_cache = Cache(self)

  def _check_connection(self):
    if self.db is None:
      raise ProgrammingError, "Cannot operate on a closed database."

  def _check_thread(self):
    self._check_connection()
    if self._check_same_thread and _thread.get_ident() != self._thread_ident:
      raise ProgrammingError, \
          "SQLite objects created in a thread can only be used in that same thread."+ \
          "The object was created in thread id %d and this is thread id %d" % \
          (self._thread_ident, _thread.get_ident())
  
  def _begin(self):
    if self._begin_statement:
      self.db.exec(self._begin_statement, None)
      self._inTransaction = 1
  
  def __del__(self):
    db = self.db
    if db is None: return
    self._statement_cache = None
    self.db = None
    db.close()

  def __call__(self, sql):
    self._check_thread()
    return self.db.compile(sql)

  def cursor(self, factory=None, row_factory=None):
    """Return a cursor for the connection."""
    self._check_thread()
    if factory is None:
      factory = Cursor
    if row_factory is None:
      row_factory = self.row_factory
    cursor = factory(self, row_factory=row_factory)
    self._cursors.append(_ref(cursor))
    return cursor

  def _reset_all_statements(self):
    self._cursors = [c for c in self._cursors if c() is not None]
    for c in self._cursors:
      c = c()
      if c is not None and hasattr(c, '_reset'):
        c._reset()
  
  def close(self):
    """Closes the connection."""
    db = self.db
    if db is None: return
    self._check_thread()
    self._reset_all_statements()
    self._statement_cache = None
    self.db = None
    return db.close()

  def commit(self):
    """Commit the current transaction."""
    self._check_thread()
    if self._inTransaction:
      self._reset_all_statements()
      self.db.exec("COMMIT", None)
      self._inTransaction = 0

  def rollback(self):
    """Roll back the current transaction."""
    self._check_thread()
    if self._inTransaction:
      self._reset_all_statements()
      self.db.exec("ROLLBACK", None)
      self._inTransaction = 0

  def create_function(self, name, nargs, func):
    """Creates a new function. Non-standard."""
    if func is not None and not callable(func):
      raise TypeError, "parameter must be callable"
    self._check_thread()
    key = name,nargs
    if func is None:
      if self._user_functions.has_key(key):
        self._user_functions[key].connection = None
        self._user_functions[key].func = None
        del self._user_functions[key]
    else:
      if self._user_functions.has_key(key):
        self._user_functions[key].connection = None
        self._user_functions[key].func = None
      func = self._user_functions[key] = self._UserFunction(self, func)
    try:
      return self.db.create_function(name, nargs, func)
    except _Exception, err:
      dberr = self.db.last_error()
      raise OperationalError, \
            "SQLite.Exception: create_function: name=%s, nargs=%d, func=%s, errcode=%d, errtext=%s, errdetails=%s" % \
            (name, nargs, func, dberr, self.db.error_string(dberr), err.getMessage())

  def create_aggregate(self, name, nargs, func):
    """Creates a new aggregate. Non-standard."""
    if func is not None and not callable(func):
      raise TypeError, "parameter must be callable"
    self._check_thread()
    key = name,nargs
    if func is None:
      if self._user_functions.has_key(key):
        self._user_functions[key].connection = None
        self._user_functions[key].func = None
        del self._user_functions[key]
    else:
      if self._user_functions.has_key(key):
        self._user_functions[key].connection = None
        self._user_functions[key].func = None
      func = self._user_functions[key] = self._UserFunction(self, func)
    try:
      return self.db.create_aggregate(name, nargs, func)
    except _Exception, err:
      dberr = self.db.last_error()
      raise OperationalError, \
            "SQLite.Exception: create_aggregate: name=%s, nargs=%d, func=%s, errcode=%d, errtext=%s, errdetails=%s" % \
            (name, nargs, func, dberr, self.db.error_string(dberr), err.getMessage())

  def create_collation(self, name, func):
    """Creates a collation function. Non-standard."""
    if func is not None and not callable(func):
      raise TypeError, "parameter must be callable"
    self._check_thread()
    raise NotImplementedError, "Connection.create_collation"
    return self.db.create_collation(name, func)

  def set_authorizer(self, func):
    """Sets authorizer callback. Non-standard."""
    self._check_thread()
    key = None
    if func is None:
      if self._user_functions.has_key(key):
        self._user_functions[key].connection = None
        self._user_functions[key].func = None
        del self._user_functions[key]
    else:
      if self._user_functions.has_key(key):
        self._user_functions[key].connection = None
        self._user_functions[key].func = None
      func = self._user_functions[key] = self._UserAuthorizer(self, func)
    try:
      return self.db.set_authorizer(func)
    except _Exception, err:
      dberr = self.db.last_error()
      raise OperationalError, \
            "SQLite.Exception: set_authorizer: name=%s, nargs=%d, func=%s, errcode=%d, errtext=%s, errdetails=%s" % \
            (name, nargs, func, dberr, self.db.error_string(dberr), err.getMessage())

  def execute(self, sql, args=None):
    """Executes a SQL statement. Non-standard."""
    return self.cursor().execute(sql, args)

  def executemany(self, sql, args=None):
    """Repeatedly executes a SQL statement. Non-standard."""
    return self.cursor().executemany(sql, args)

  def executescript(self, sql, args=None):
    """Executes a multiple SQL statements at once. Non-standard."""
    return self.cursor().executescript(sql, args)

  def interrupt(self):
    """Abort any pending database operation. Non-standard."""
    self._check_connection()
    return self.db.interrupt()

  def _get_total_changes(self):
    self._check_connection()
    return self._total_changes

  def _set_isolation_level(self, new_isolation_level):
    self._isolation_level = new_isolation_level
    if new_isolation_level is not None:
      self._begin_statement = "BEGIN "+new_isolation_level
    else:
      self.commit()
      self._begin_statement = None

  def _get_isolation_level(self):
    return self._isolation_level

  def _get_dbversion(self):
    self._check_connection()
    return self.db.dbversion()

  total_changes = property(_get_total_changes)
  isolation_level = property(_get_isolation_level, _set_isolation_level)
  dbversion = property(_get_dbversion)

class Cursor:
  """SQLite database cursor class."""
  class Callback(_Callback):
    def __init__(self, cursor):
      self.cursor = cursor

    def columns(self, coldata):
      if self.cursor._next_row is not None:
        raise InternalError, "Previous data not cleaned"
      self.cursor._last_columns = tuple(coldata)
      self.cursor._last_types = None

    def types(self, types):
      if self.cursor._last_columns is None:
        raise InternalError, "columns not called"
      if self.cursor._next_row is not None:
        raise InternalError, "Previous data not cleaned"
      self.cursor._last_types = tuple(types)

    def newrow(self, rowdata):
      if self.cursor._last_columns is None:
        raise InternalError, "columns not called"
      if self.cursor._next_row is not None:
        raise InternalError, "Previous data not cleaned"
      if self.cursor.description is None:
        self.cursor._build_description()
        self.cursor._build_row_cast_map()
      if len(self.cursor.description) != len(rowdata):
        raise InternalError, "Invalid row length"
      row = []
      for i in xrange(len(rowdata)):
        val = rowdata[i]
        coltype = None
        if self.cursor._last_types is not None:
          coltype = self.cursor._last_types[i]
          if coltype:
            coltype = coltype.strip().lower()
        if val is not None:
          if (self.cursor._row_cast_map is not None and
              self.cursor._row_cast_map[i] is not None):
            val = self.cursor._row_cast_map[i](val)
          else:
            val = _cast_value(val, coltype, self.cursor.connection.text_factory)
        row.append(val)
      row = tuple(row)
      self.cursor._next_row = row
      return 0

  def __init__(self, connection, row_factory=None):
    self._statement = None
    self.connection = None
    if not isinstance(connection, Connection):
      raise TypeError, "Invalid connection instance passed to Cursor constructor"
    self.connection = connection
    self._row_cast_map = None
    self._last_columns = None
    self._last_types = None
    self._last_sql = None
    self._next_row = None
    self._on_eos = 1 # End Of Set (=last row prefetched)
    self.description = None
    self.lastrowid = None
    self.arraysize = 1
    self.rowcount = -1
    self.row_factory = row_factory
    self._cb = self.Callback(self)
    self.connection._check_thread()

  def __del__(self):
    if self._statement is not None:
      self._statement.stop()
    self._statement = None
    self._on_eos = 1
    self.connection = None

  def _reset(self):
    if self._statement is not None:
      self._statement.stop()
    self._statement = None
    self._on_eos = 1

  def _build_description(self):
    self.description = []
    if self._last_columns is None or self._last_types is None:
      raise InternalError, "Different number of types and names of columns %s !~ %s (%s)" % \
                           (repr(self._last_columns), repr(self._last_types), self._last_sql)
    if len(self._last_columns) != len(self._last_types):
      raise InternalError, "Different number of types and names of columns %s !~ %s (%s)" % \
                           (repr(self._last_columns), repr(self._last_types), self._last_sql)
    for i in xrange(len(self._last_columns)):
      colname = self._last_columns[i]
      if colname is not None:
        colname = colname.split('[',1)[0].strip()
      coltype = self._last_types[i]
      self.description.append((colname,coltype,None,None,None,None,None))

  def _build_row_cast_map(self):
    if not self.connection._detect_types: return
    if self._last_columns is None or self._last_types is None:
      raise InternalError, "Different number of types and names of columns %s !~ %s (%s)" % \
                           (repr(self._last_columns), repr(self._last_types), self._last_sql)
    if len(self._last_columns) != len(self._last_types):
      raise InternalError, "Different number of types and names of columns %s !~ %s (%s)" % \
                           (repr(self._last_columns), repr(self._last_types), self._last_sql)
    self._row_cast_map = []
    for i in xrange(len(self._last_columns)):
      converter = None
      if self.connection._detect_types & PARSE_COLNAMES:
        colname = self._last_columns[i]
        if '[' in colname and colname[-1:] == ']':
          key = colname.split('[',1)[1][:-1]
          converter = _get_converter(key)
      if converter is None and self.connection._detect_types & PARSE_DECLTYPES:
        coltype = self._last_types[i]
        if coltype is not None:
          converter = _get_converter(coltype)
      self._row_cast_map.append(converter)

  def _check_cursor(self):
    if self.connection is None:
      raise ProgrammingError, "Cannot operate on a closed cursor"
    self.connection._check_thread()

  def execute(self, sql, args=None):
    """Executes a SQL statement."""
    if type(sql) not in (type(''),type(u'')):
      raise ValueError, "sql must be str or unicode not "+str(type(sql))
    self._check_cursor()
    if args:
      args = _prepare_args(args)
    sql = _substitute_args(sql, args)
    if _count_statements(sql)>1:
      raise Warning, "You can only execute one statement at a time."

    #initialize attributes
    self._last_columns = None
    self._last_types = None
    self.description = None
    self._next_row = None
    self._reset()
    self.rowcount = -1

    #process transaction
    sqltype = _detect_statement_type(sql)
    if sqltype in (STATEMENT_UPDATE,STATEMENT_DELETE,STATEMENT_INSERT,STATEMENT_REPLACE):
      if not self.connection._inTransaction:
        self.connection._begin()
    elif sqltype == STATEMENT_OTHER:
      if self.connection._inTransaction:
        self.connection.commit()

    #compile SQL statement
    import java.lang
    try:
      self._last_sql = sql
      self._statement = self.connection._statement_cache.get(sql)
      dberr = self.connection.db.last_error()
      if dberr: raise DatabaseError, db.error_string(dberr)
      self._on_eos = not self._statement.step(self._cb)
      self.last_rowid = self.connection.db.last_insert_rowid()
      changes = self.connection.db.changes()
    except _Exception, err:
      db = self.connection.db
      dberr = db.last_error()
      raise OperationalError, \
            "SQLite.Exception: execute.sql=%s, args=%s, errcode=%d, errtext=%s, errdetails=%s" % \
            (sql, args, dberr, db.error_string(dberr), err.getMessage())
    #except java.lang.ArrayIndexOutOfBoundsException, err:
    #  raise ProgrammingError, err
    #except TypeError, err:
    #  print 'Cursor.execute: TypeError:', repr(sql), repr(args)
    #  raise

    if changes:
      self.connection._total_changes += changes
      self.rowcount = changes
    else:
      self.rowcount = 0
      if self._next_row is not None:
        self.rowcount += 1
    return self

  def executemany(self, sql, largs):
    """Repeatedly executes a SQL statement."""
    if type(sql) not in (type(''),type(u'')):
      raise ValueError, "sql must be str or unicode not "+str(type(sql))

    #initialize attributes
    self._check_cursor()
    self._last_columns = None
    self._last_types = None
    self.description = None
    self._next_row = None
    self._reset()
    self.rowcount = 0

    #process transaction
    sqltype = _detect_statement_type(sql)
    if sqltype in (STATEMENT_UPDATE,STATEMENT_DELETE,STATEMENT_INSERT,STATEMENT_REPLACE):
      if not self.connection._inTransaction:
        self.connection._begin()
    elif sqltype == STATEMENT_OTHER:
      if self.connection._inTransaction:
        self.connection.commit()
    elif sqltype == STATEMENT_SELECT:
      raise ProgrammingError, "You cannot execute SELECT statements in executemany()."

    #loop over args
    for args in largs:
      args = _prepare_args(args)
      self._last_sql = _substitute_args(sql, args)
      try:
        self.connection.db.exec(self._last_sql, self._cb)
        changes = self.connection.db.changes()
        self.last_rowid = self.connection.db.last_insert_rowid()
      except _Exception, err:
        db = self.connection.db
        dberr = db.last_error()
        raise OperationalError, \
              "SQLite.Exception: executemany.sql=%s, args=%s, errcode=%d, errtext=%s, errdetails=%s" % \
              (sql, args, dberr, db.error_string(dberr), err.getMessage())
      self.connection._total_changes += changes
      self.rowcount += changes
    return self

  def executescript(self, sql, args=None):
    """Executes a multiple SQL statements at once. Non-standard."""
    if type(sql) not in (type(''),type(u'')):
      raise ValueError, "sql must be str or unicode not "+str(type(sql))

    self._check_cursor()
    if args:
      args = _prepare_args(args)
    sql = _substitute_args(sql, args)

    #commit first as done on C version
    self.connection.commit()

    if not complete_statement(sql):
      raise ProgrammingError, "you did not provide a complete SQL statement"

    self.rowcount = -1
    self._on_eos = 1
    self._next_row = None
    self._last_columns = None
    self._last_types = None
    self.description = None
    self._last_sql = sql
    try:
      self.connection.db.exec(sql, None)
      changes = self.connection.db.changes()
      self.last_rowid = self.connection.db.last_insert_rowid()
    except _Exception, err:
      db = self.connection.db
      dberr = db.last_error()
      raise OperationalError, \
            "SQLite.Exception: executescript.sql=%s, args=%s, errcode=%d, errtext=%s, errdetails=%s" % \
            (sql, args, dberr, db.error_string(dberr), err.getMessage())
    self.connection._total_changes += changes
    self.rowcount = changes

    return self

  def fetchone(self):
    """Fetches several rows from the resultset."""
    self._check_cursor()
    if not self._next_row: return None
    next_row = self._next_row
    self._next_row = None
    if self.row_factory is not None:
      next_row = self.row_factory(self, next_row)
    if not self._on_eos:
      self._on_eos = not self._statement.step(self._cb)
      if self._next_row is not None:
        assert not self._on_eos
        self.rowcount += 1
      else:
        assert self._on_eos
        while self._statement.compile():
          self._last_columns = None
          self._last_types = None
          self.description = None
          self._on_eos = not self._statement.step(self._cb)
          if self._next_row is not None:
            assert not self._on_eos
            self.rowcount += 1
            break
          else:
            assert self._on_eos
    return next_row

  def fetchmany(self, maxrows=None):
    """Fetches all rows from the resultset."""
    if maxrows is None: maxrows = self.arraysize
    res = []
    for i in xrange(maxrows):
      row = self.fetchone()
      if row is None: return res
      res.append(row)
    return res

  def fetchall(self):
    """Fetches one row from the resultset."""
    res = []
    row = self.fetchone()
    while row is not None:
      res.append(row)
      row = self.fetchone()
    return res

  def close(self):
    """Closes the cursor."""
    if self.connection is None: return
    self._check_cursor()
    self._reset()
    self.connection = None

  def __iter__(self):
    return self

  def next(self):
    row = self.fetchone()
    if row is None: raise StopIteration
    return row

  def setinputsizes(self, sizes):
    """Required by DB-API. Does nothing in pysqlite."""
    pass

  def setoutputsize(self, size, column=None):
    """Required by DB-API. Does nothing in pysqlite."""
    pass

class Cache:
  def __init__(self, factory, size=None):
    self.factory = factory

  def get(self, *args):
    return self.factory(*args)

  def display(self):
    print "No SQL caching due to pre-binding required"

#No SQL caching due to pre-binding required
#class Cache:
#  def __init__(self, factory, size=None):
#    self.factory = factory
#    if size is None: size = 10
#    if type(size) != type(0):
#      raise TypeError, "type(size) must be int, not "+str(type(size))
#    if size < 5: size = 5
#    self.size = size
#    self._cache = {}
#
#  def get(self, key):
#    if self._cache.has_key(key):
#      node = self._cache[key]
#      node[0] += 1
#    else:
#      if len(self._cache) >= size:
#        items = self._cache.items()
#        if items:
#          items.sort(lambda a,b:cmp(a[1][0],b[1][0]))
#          del self._cache[items[0][0]]
#      node = [0, self.factory(key)]
#      self._cache[key] = node
#    return node[1]
#
#  def display(self):
#    items = self._cache.items()
#    if items:
#      items.sort(lambda a,b:cmp(a[1][0],b[1][0]))
#      keys = zip(*items)[0]
#      keys.append(None)
#      prevkey = None
#      nextkey = keys[0]
#      for i in xrange(1,len(keys)):
#        key = nextkey
#        nextkey = keys[i]
#        print '%s <- %s ->%s' % (prevkey, key, nextkey)
#        prevkey = key

class Row:
  def __init__(self, cursor, rowdata):
    self.description = cursor.description
    self.rowdata = rowdata

  def __len__(self):
    return len(self.rowdata)

  def __getitem__(self, index):
    if type(index) in (type(0),type(0l)):
      return self.rowdata[index]
    for i in xrange(len(self.description)):
      if index.lower() == self.description[i][0].lower():
        return self.rowdata[i]
    raise KeyError, index

  def __repr__(self):
    return 'Row('+(', '.join([n[0]+'='+repr(v) for n,v in zip(self.description,self.rowdata)]))+')'

OptimizedUnicode = unicode

from jarray import array as _jarray

class buffer:
  """Java array of characters - jarray.array(x, 'c')"""
  def __init__(self, x):
    self.val = _jarray(x, 'c')
    for attr in ['__cmp__', '__delattr__', '__delitem__', '__delslice__', '__eq__',
                 '__finditem__', '__ge__', '__getitem__', '__getslice__', '__gt__',
                 '__hash__', '__iter__', '__le__', '__len__', '__lt__', '__ne__',
                 '__nonzero__', '__repr__', '__setattr__', '__setitem__',
                 '__setslice__', '__str__', '__tojava__', 'append', 'array',
                 'byteswap', 'count', 'extend', 'fromfile', 'fromlist',
                 'fromstring', 'getItemsize', 'index', 'insert', 'itemsize',
                 'pop', 'remove', 'reverse', 'tofile', 'tolist', 'tostring']:
      setattr(self, attr, getattr(self.val, attr))

  def __add__(self, b):
    if isinstance(b, buffer):
      return buffer(self.val+b.val)
    return buffer(self.val+b)

  def __mul__(self, b):
    if isinstance(b, buffer):
      return Binary(self.val*b.val)
    return buffer(self.val*b)

  def __rmul__(self, b):
    if isinstance(b, buffer):
      return buffer(b.val*self.val)
    return buffer(b*self.val)

  def zeros(self, l):
    return buffer(self.val.zeros(l))

def _detect_statement_type(sql):
  if not sql:
    return STATEMENT_INVALID
  sqlcmd = _sql_strip(sql)[:7].strip().lower()
  if not sqlcmd:
    return STATEMENT_INVALID
  elif sqlcmd == "select":
    return STATEMENT_SELECT
  elif sqlcmd == "insert":
    return STATEMENT_INSERT
  elif sqlcmd == "update":
    return STATEMENT_UPDATE
  elif sqlcmd == "delete":
    return STATEMENT_DELETE
  elif sqlcmd == "replace":
    return STATEMENT_REPLACE
  return STATEMENT_OTHER

def _sql_strip(sql):
  sql = sql.strip()
  sql = filter(None, sql.split('\n'))
  in_comment = 0
  while sql:
    if in_comment:
      i = sql[0].find('*/')
      if i>=0:
        sql[0] = sql[0][i+2:]
        in_comment = 0
      else:
        del sql[0]
        continue
    check = sql[0].strip()
    if check.startswith('--') or check.startswith('//'):
      del sql[0]
    elif check.startswith('/*'):
      del sql[0]
      in_comment = 1
    else:
      break
  return '\n'.join(sql)

def _count_statements(sql):
  start = 0
  end = sql.find(';',start)
  count = 0
  while end >= 0:
    if complete_statement(sql[start:end+1]) and _sql_strip(sql[start:end]):
      count += 1
    start = end+1
    end = sql.find(';',start)
  if _sql_strip(sql[start:]):
    count += 1
  return count

def _prepare_args(args):
  if type(args) == type({}):
    args = args.copy()
    l = args.items()
  else:
    args = list(args[:])
    l = enumerate(args)
  for k,val in l:
    try: args[k] = val = adapt(val)
    except ProgrammingError: pass
  return args

_bind = None
def _get_bindings(sql):
  global _bind
  if _bind is None:
    _bind = _re.compile('(\?|:(?:[a-z_][a-z0-9_]*))', _re.I)
  b = _bind.split(sql)
  nob = []
  for i in xrange(1,len(b),2):
    if not complete_statement(''.join(b[:i-1])+';'):
      nob.append(i)
  nob.reverse()
  for i in nob:
    b[i-1] = ''.join(b[i-1:i+2])
    del b[i:i+2]
  assert len(b)%2 == 1, "Internal parsing error "+repr(b)
  return b

def _quote(arg):
  if arg is None:
    return 'NULL'
  if type(arg) in (int,long,float):
    return str(arg)
  if type(arg) in (str,unicode):
    #if arg.isunicode():
    arg = arg.encode('utf-8')
    return "'%s'" % (arg.replace("'","''"),)
  raise InterfaceError, "Unsupported/non-adaptable type "+str(type(arg))

def _substitute_args(sql, args):
  #if sql.isunicode():
  sql = sql.encode('utf-8')
  b = _get_bindings(sql)
  if len(b) == 1: return sql
  keys = b[1::2]
  if not args:
    raise ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied." % (len(keys),0)
  if keys[0] == '?':
    if filter(lambda s:s!='?', keys):
      raise ProgrammingError, "Incorrect statament. Both named and unnamed bindings used."
    if type(args) == type({}):
      raise ProgrammingError, "Incorrect bindings supplied. For unnamed bindings list must be passed."
    if len(keys) != len(args):
      raise ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied." % (len(keys),len(args))
    try:
      return sql.replace('%','%%').replace('?', '%s') % tuple(map(_quote, args))
    except TypeError, err:
      raise ProgrammingError, str(err)
  else:
    if filter(lambda s:s=='?', keys):
      raise ProgrammingError, "Incorrect statament. Both named and unnamed bindings used."
    if type(args) != type({}):
      raise ProgrammingError, "Incorrect bindings supplied. For named bindings dictionary must be passed."
    unused = {}
    for k in args.keys():
      unused[k] = 1
    for i in xrange(len(b)):
      if i%2 == 1:
        k = b[i][1:]
        if not args.has_key(k):
          raise ProgrammingError, "You did not supply a value for binding :%s." % (k,)
        b[i] = _quote(args[k])
        if unused.has_key(k):
          del unused[k]
    if unused:
      raise ProgrammingError, "There are unused named bindings: "+repr(unused.keys())
    return ''.join(b)

def _cast_value(val, coltype=None, text_factory=None):
  if coltype is None:
    if type(val) == type(''):
      try: val = int(val)
      except ValueError: pass
    if type(val) == type(''):
      try: val = long(val)
      except ValueError: pass
    if type(val) == type(''):
      try: val = float(val)
      except ValueError: pass
    if type(val) == type('') and text_factory is not None:
      val = val.decode('utf-8')
      #if text_factory is unicode:
      #  val = val.decode('utf-8')
      #el
      if text_factory not in (str,unicode):
        val = text_factory(val)
    #print '_cast_value: result:', repr(val)
    return val
  if type(val) == type('') and coltype.find('int') >= 0:
    try: val = int(val)
    except ValueError:
      try: val = long(val)
      except ValueError: pass
  elif type(val) == type('') and (
       coltype.find('number') >= 0 or coltype.find('float') >= 0 or
       coltype.find('decimal') >= 0 or coltype.find('double') >= 0 or
       coltype.find('real') >= 0 or coltype.find('numeric') >= 0):
    val = float(val)
  elif type(val) == type('') and coltype == 'binary':
    val = Binary(val)
  elif type(val) == type('') and text_factory is not None:
    val = val.decode('utf-8')
    #if text_factory is unicode or text_factory is None:
    #  val = val.decode('utf-8')
    #el
    if text_factory not in (str,unicode):
      val = text_factory(val)
  return val

def _get_converter(key):
  return converters.get(key.upper())

def connect(*args, **kwargs):
  """Creates a connection."""
  factory = Connection
  if kwargs.has_key('factory'):
    if kwargs['factory'] is not None:
      factory = kwargs['factory']
    del kwargs['factory']
  return factory(*args, **kwargs)

def complete_statement(statement):
  """Checks if a string contains a complete SQL statement. Non-standard."""
  return _Database.complete(statement)

def enable_shared_cache(do_enable):
  """Enable or disable shared cache mode for the calling thread. Experimental/Non-standard."""
  raise NotImplementedError, "enable_shared_cache"

def register_adapter(type_, adapter):
  """Registers an adapter with pysqlite's adapter registry. Non-standard."""
  adapters[type_,PrepareProtocol] = adapter

def register_converter(name, converter):
  """Registers a converter with pysqlite. Non-standard."""
  converters[name.upper()] = converter

def adapt(obj, proto=PrepareProtocol, alt=None):
  """adapt(obj, protocol, alternate) -> adapt obj to given protocol. Non-standard."""
  type_ = type(obj)
  adapter = adapters.get((type_,proto))
  if adapter is not None:
    return adapter(obj)
  if hasattr(proto, '__adapt__'):
    adapted = proto.__adapt__(obj)
    if adapted is not None:
      return adapted
  if hasattr(obj, '__conform__'):
    adapted = obj.__conform__(proto)
    if adapted is not None:
      return adapted
  raise ProgrammingError, "can't adapt"

def enable_callback_tracebacks(do_enable):
  """Enable or disable callback functions throwing errors to stderr."""
  _enable_callback_tracebacks = do_enable