Initial import
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
# The default ``config.py``
|
||||
|
||||
|
||||
def set_prefs(prefs):
|
||||
"""This function is called before opening the project"""
|
||||
|
||||
# Specify which files and folders to ignore in the project.
|
||||
# Changes to ignored resources are not added to the history and
|
||||
# VCSs. Also they are not returned in `Project.get_files()`.
|
||||
# Note that ``?`` and ``*`` match all characters but slashes.
|
||||
# '*.pyc': matches 'test.pyc' and 'pkg/test.pyc'
|
||||
# 'mod*.pyc': matches 'test/mod1.pyc' but not 'mod/1.pyc'
|
||||
# '.svn': matches 'pkg/.svn' and all of its children
|
||||
# 'build/*.o': matches 'build/lib.o' but not 'build/sub/lib.o'
|
||||
# 'build//*.o': matches 'build/lib.o' and 'build/sub/lib.o'
|
||||
prefs['ignored_resources'] = ['*.pyc', '*~', '.ropeproject',
|
||||
'.hg', '.svn', '_svn', '.git']
|
||||
|
||||
# Specifies which files should be considered python files. It is
|
||||
# useful when you have scripts inside your project. Only files
|
||||
# ending with ``.py`` are considered to be python files by
|
||||
# default.
|
||||
#prefs['python_files'] = ['*.py']
|
||||
|
||||
# Custom source folders: By default rope searches the project
|
||||
# for finding source folders (folders that should be searched
|
||||
# for finding modules). You can add paths to that list. Note
|
||||
# that rope guesses project source folders correctly most of the
|
||||
# time; use this if you have any problems.
|
||||
# The folders should be relative to project root and use '/' for
|
||||
# separating folders regardless of the platform rope is running on.
|
||||
# 'src/my_source_folder' for instance.
|
||||
#prefs.add('source_folders', 'src')
|
||||
|
||||
# You can extend python path for looking up modules
|
||||
#prefs.add('python_path', '~/python/')
|
||||
|
||||
# Should rope save object information or not.
|
||||
prefs['save_objectdb'] = True
|
||||
prefs['compress_objectdb'] = False
|
||||
|
||||
# If `True`, rope analyzes each module when it is being saved.
|
||||
prefs['automatic_soa'] = True
|
||||
# The depth of calls to follow in static object analysis
|
||||
prefs['soa_followed_calls'] = 0
|
||||
|
||||
# If `False` when running modules or unit tests "dynamic object
|
||||
# analysis" is turned off. This makes them much faster.
|
||||
prefs['perform_doa'] = True
|
||||
|
||||
# Rope can check the validity of its object DB when running.
|
||||
prefs['validate_objectdb'] = True
|
||||
|
||||
# How many undos to hold?
|
||||
prefs['max_history_items'] = 32
|
||||
|
||||
# Shows whether to save history across sessions.
|
||||
prefs['save_history'] = True
|
||||
prefs['compress_history'] = False
|
||||
|
||||
# Set the number spaces used for indenting. According to
|
||||
# :PEP:`8`, it is best to use 4 spaces. Since most of rope's
|
||||
# unit-tests use 4 spaces it is more reliable, too.
|
||||
prefs['indent_size'] = 4
|
||||
|
||||
# Builtin and c-extension modules that are allowed to be imported
|
||||
# and inspected by rope.
|
||||
prefs['extension_modules'] = []
|
||||
|
||||
# Add all standard c-extensions to extension_modules list.
|
||||
prefs['import_dynload_stdmods'] = True
|
||||
|
||||
# If `True` modules with syntax errors are considered to be empty.
|
||||
# The default value is `False`; When `False` syntax errors raise
|
||||
# `rope.base.exceptions.ModuleSyntaxError` exception.
|
||||
prefs['ignore_syntax_errors'] = False
|
||||
|
||||
# If `True`, rope ignores unresolvable imports. Otherwise, they
|
||||
# appear in the importing namespace.
|
||||
prefs['ignore_bad_imports'] = False
|
||||
|
||||
|
||||
def project_opened(project):
|
||||
"""This function is called after opening the project"""
|
||||
# Do whatever you like here!
|
||||
@@ -0,0 +1,154 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: JayDeBeApi
|
||||
Version: 0.1
|
||||
Summary: A bridge from JDBC database drivers to Python DB-API.
|
||||
Home-page: https://code.launchpad.net/jaydebeapi
|
||||
Author: Bastian Bowe
|
||||
Author-email: bastian.bowe@gmail.com
|
||||
License: GNU LGPL
|
||||
Description: =====================================================================
|
||||
JayDeBeApi - bridge from JDBC Database drivers to Python DB-API
|
||||
=====================================================================
|
||||
|
||||
The JayDeBeApi library allows you to connect from Python code to
|
||||
databases using Java `JDBC
|
||||
<http://java.sun.com/products/jdbc/overview.html>`_. It provides a
|
||||
Python DB-API_ v2.0 to that database.
|
||||
|
||||
It works on ordinary Python (cPython) using the JPype_ Java
|
||||
integration or on `Jython <http://www.jython.org/>`_ to make use of
|
||||
the Java JDBC driver.
|
||||
|
||||
It has been tested with `Hypersonic SQL (HSQLDB)
|
||||
<http://hsqldb.org/>`_ and `IBM DB2
|
||||
<http://www.ibm.com/software/data/db2/>`_ for z/OS.
|
||||
|
||||
In contrast to zxJDBC from the Jython project JayDeBeApi let's you
|
||||
access a database with Jython AND Python with only minor code
|
||||
modifications. JayDeBeApi's future goal is to provide a unique and
|
||||
fast interface to different types of JDBC-Drivers through a flexible
|
||||
plug-in mechanism.
|
||||
|
||||
.. contents::
|
||||
|
||||
Install
|
||||
=======
|
||||
|
||||
You can get and install JayDeBeApi with `easy_install
|
||||
<http://peak.telecommunity.com/DevCenter/EasyInstall>`_ ::
|
||||
|
||||
$ easy_install JayDeBeApi
|
||||
|
||||
If you want to install JayDeBeApi in Jython make sure to have
|
||||
EasyInstall available for it.
|
||||
|
||||
Or you can get a copy of the source branch using `bzr
|
||||
<http://bazaar.canonical.com/>`_ by running ::
|
||||
|
||||
$ bzr branch lp:jaydebeapi
|
||||
|
||||
and install it with ::
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
or if you are using Jython use ::
|
||||
|
||||
$ jython setup.py install
|
||||
|
||||
It has been tested with Jython 2.5.2.
|
||||
|
||||
If you are using cPython ensure that you have installed JPype_
|
||||
properly. It has been tested with JPype 0.5.4.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Basically you just import the ``jaydebeapi`` Python module and execute
|
||||
the ``connect`` method. This gives you a DB-API_ conform connection to
|
||||
the database.
|
||||
|
||||
The first argument to ``connect`` is the name of the Java driver
|
||||
class. The rest of the arguments are internally passed to the Java
|
||||
``DriverManager.getConnection`` method. See the Javadoc of
|
||||
``DriverManager`` class for details.
|
||||
|
||||
Here is an example:
|
||||
|
||||
>>> import jaydebeapi
|
||||
>>> conn = jaydebeapi.connect('org.hsqldb.jdbcDriver',
|
||||
... 'jdbc:hsqldb:mem', 'SA', '')
|
||||
>>> curs = conn.cursor()
|
||||
>>> curs.execute('create table CUSTOMER'
|
||||
... '("CUST_ID" INTEGER not null,'
|
||||
... ' "NAME" VARCHAR not null,'
|
||||
... ' primary key ("CUST_ID"))'
|
||||
... )
|
||||
>>> curs.execute("insert into CUSTOMER values (1, 'John')")
|
||||
>>> curs.execute("select * from CUSTOMER")
|
||||
>>> curs.fetchall()
|
||||
[(1, u'John')]
|
||||
|
||||
You probably have to configure Jython or JPype to actually be able to
|
||||
access the database driver's jar files. If I want to connect to a HSQL
|
||||
in memory database on my Ubuntu machine I'm starting Python by running ::
|
||||
|
||||
$ JAVA_HOME=/usr/lib/jvm/java-6-openjdk python
|
||||
|
||||
Now I have to configure JPype
|
||||
|
||||
>>> jar = '/path/to/my/driver/hsqldb.jar'
|
||||
>>> args='-Djava.class.path=%s' % jar
|
||||
>>> jpype.startJVM(jvm_path, args)
|
||||
|
||||
or in Jython I have to
|
||||
|
||||
>>> jar = '/path/to/my/driver/hsqldb.jar'
|
||||
>>> import sys
|
||||
>>> sys.path.append(jar)
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Please submit `bugs and patches
|
||||
<https://bugs.launchpad.net/jaydebeapi>`_. All contributors will be
|
||||
acknowledged. Thanks!
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
JayDeBeApi is released under the GNU Lesser General Public license
|
||||
(LGPL). See the file ``COPYING`` and ``COPYING.LESSER`` in the
|
||||
distribution for details.
|
||||
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
- 0.1
|
||||
|
||||
- Initial release
|
||||
|
||||
To do
|
||||
=====
|
||||
|
||||
- Extract Java calls to seperate Java methods to increase performance.
|
||||
- Check if https://code.launchpad.net/dbapi-compliance can help making
|
||||
JayDeBeApi more DB-API complient.
|
||||
- Test it on different databases and provide a flexible db specific
|
||||
pluign mechanism.
|
||||
- SQLAlchemy modules (seperate project)
|
||||
|
||||
.. _DB-API: http://www.python.org/dev/peps/pep-0249/
|
||||
.. _JPype: http://jpype.sourceforge.net/
|
||||
|
||||
Keywords: db api java jdbc bridge connect sql jpype jython
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 3 - Alpha
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
||||
Classifier: Programming Language :: Java
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Topic :: Database
|
||||
Classifier: Topic :: Software Development :: Libraries :: Java Libraries
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
@@ -0,0 +1,7 @@
|
||||
setup.py
|
||||
src/JayDeBeApi.egg-info/PKG-INFO
|
||||
src/JayDeBeApi.egg-info/SOURCES.txt
|
||||
src/JayDeBeApi.egg-info/dependency_links.txt
|
||||
src/JayDeBeApi.egg-info/top_level.txt
|
||||
src/jaydebeapi/__init__.py
|
||||
src/jaydebeapi/dbapi2.py
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
jaydebeapi
|
||||
@@ -0,0 +1 @@
|
||||
from dbapi2 import *
|
||||
@@ -0,0 +1,385 @@
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010 Bastian Bowe
|
||||
#
|
||||
# This file is part of JayDeBeApi.
|
||||
# JayDeBeApi is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# JayDeBeApi is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with JayDeBeApi. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
import exceptions
|
||||
import time
|
||||
import sys
|
||||
|
||||
_jdbc_connect = None
|
||||
|
||||
def _jdbc_connect_jython(jclassname, *args):
|
||||
# register driver for DriverManager
|
||||
__import__(jclassname)
|
||||
from java.sql import DriverManager
|
||||
return DriverManager.getConnection(*args)
|
||||
|
||||
def _prepare_jython():
|
||||
global _jdbc_connect
|
||||
_jdbc_connect = _jdbc_connect_jython
|
||||
# TODO: find solution for jython
|
||||
# Binary = buffer
|
||||
|
||||
def _jdbc_connect_jpype(jclassname, *args):
|
||||
import jpype
|
||||
if not jpype.isJVMStarted():
|
||||
jpype.startJVM(jpype.getDefaultJVMPath())
|
||||
if not jpype.isThreadAttachedToJVM():
|
||||
jpype.attachThreadToJVM()
|
||||
# register driver for DriverManager
|
||||
jpype.JClass(jclassname)
|
||||
return jpype.java.sql.DriverManager.getConnection(*args)
|
||||
|
||||
def _prepare_jpype():
|
||||
global _jdbc_connect
|
||||
_jdbc_connect = _jdbc_connect_jpype
|
||||
# TODO: doesn't work for Jython
|
||||
# global Binary
|
||||
# Binary = buffer
|
||||
|
||||
if sys.platform.lower().startswith('java'):
|
||||
_prepare_jython()
|
||||
else:
|
||||
_prepare_jpype()
|
||||
|
||||
apilevel = '2.0'
|
||||
threadsafety = 1
|
||||
paramstyle = 'qmark'
|
||||
|
||||
class DBAPITypeObject(object):
|
||||
def __init__(self,*values):
|
||||
self.values = values
|
||||
def __cmp__(self,other):
|
||||
if other in self.values:
|
||||
return 0
|
||||
if other < self.values:
|
||||
return 1
|
||||
else:
|
||||
return -1
|
||||
|
||||
STRING = DBAPITypeObject("CHARACTER", "CHAR", "VARCHAR",
|
||||
"CHARACTER VARYING", "CHAR VARYING", "STRING",)
|
||||
|
||||
TEXT = DBAPITypeObject("CLOB", "CHARACTER LARGE OBJECT",
|
||||
"CHAR LARGE OBJECT", "XML",)
|
||||
|
||||
BINARY = DBAPITypeObject("BLOB", "BINARY LARGE OBJECT",)
|
||||
|
||||
NUMBER = DBAPITypeObject("INTEGER", "INT", "SMALLINT", "BIGINT",)
|
||||
|
||||
FLOAT = DBAPITypeObject("FLOAT", "REAL", "DOUBLE", "DECFLOAT")
|
||||
|
||||
DECIMAL = DBAPITypeObject("DECIMAL", "DEC", "NUMERIC", "NUM",)
|
||||
|
||||
DATE = DBAPITypeObject("DATE",)
|
||||
|
||||
TIME = DBAPITypeObject("TIME",)
|
||||
|
||||
DATETIME = DBAPITypeObject("TIMESTAMP",)
|
||||
|
||||
ROWID = DBAPITypeObject(())
|
||||
|
||||
# DB-API 2.0 Module Interface Exceptions
|
||||
class Error(exceptions.StandardError):
|
||||
pass
|
||||
|
||||
class Warning(exceptions.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
|
||||
|
||||
# DB-API 2.0 Type Objects and Constructors
|
||||
Date = datetime.date
|
||||
|
||||
Time = datetime.time
|
||||
|
||||
Timestamp = datetime.datetime
|
||||
|
||||
def DateFromTicks(ticks):
|
||||
return apply(Date, time.localtime(ticks)[:3])
|
||||
|
||||
def TimeFromTicks(ticks):
|
||||
return apply(Time, time.localtime(ticks)[3:6])
|
||||
|
||||
def TimestampFromTicks(ticks):
|
||||
return apply(Timestamp, time.localtime(ticks)[:6])
|
||||
|
||||
# DB-API 2.0 Module Interface connect constructor
|
||||
def connect(jclassname, *args):
|
||||
jconn = _jdbc_connect(jclassname, *args)
|
||||
return Connection(jconn)
|
||||
|
||||
# DB-API 2.0 Connection Object
|
||||
class Connection(object):
|
||||
|
||||
jconn = None
|
||||
|
||||
def __init__(self, jconn):
|
||||
self.jconn = jconn
|
||||
|
||||
def close(self):
|
||||
self.jconn.close()
|
||||
|
||||
def commit(self):
|
||||
return self.jconn.commit()
|
||||
|
||||
def rollback(self):
|
||||
return self.jconn.rollback()
|
||||
|
||||
def cursor(self):
|
||||
return Cursor(self)
|
||||
|
||||
# DB-API 2.0 Cursor Object
|
||||
class Cursor(object):
|
||||
|
||||
rowcount = -1
|
||||
_meta = None
|
||||
_prep = None
|
||||
_rs = None
|
||||
_description = None
|
||||
|
||||
def __init__(self, connection):
|
||||
self._connection = connection
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
if self._description:
|
||||
return self._description
|
||||
m = self._meta
|
||||
if m:
|
||||
count = m.getColumnCount()
|
||||
self._description = []
|
||||
for col in range(1, count + 1):
|
||||
size = m.getColumnDisplaySize(col)
|
||||
col_desc = ( m.getColumnName(col),
|
||||
m.getColumnTypeName(col),
|
||||
size,
|
||||
size,
|
||||
m.getPrecision(col),
|
||||
m.getScale(col),
|
||||
m.isNullable(col),
|
||||
)
|
||||
self._description.append(col_desc)
|
||||
return self._description
|
||||
|
||||
# optional callproc(self, procname, *parameters) unsupported
|
||||
|
||||
def close(self):
|
||||
self._close_last()
|
||||
self.connection = None
|
||||
|
||||
def _close_last(self):
|
||||
"""Close the resultset and reset collected meta data.
|
||||
"""
|
||||
if self._rs:
|
||||
self._rs.close()
|
||||
if self._prep:
|
||||
self._prep.close()
|
||||
self._rs = None
|
||||
self._meta = None
|
||||
self._description = None
|
||||
|
||||
def _set_stmt_parms(self, prep_stmt, *parameters):
|
||||
for i in range(len(parameters)):
|
||||
sqltype = TYPE_MAP[type(parameters[i])]
|
||||
setter = getattr(prep_stmt, 'set%s' % METHOD_MAP[sqltype])
|
||||
setter(i + 1, parameters[i])
|
||||
|
||||
def execute(self, operation, *parameters):
|
||||
self._close_last()
|
||||
self._prep = self._connection.jconn.prepareStatement(operation)
|
||||
self._set_stmt_parms(self._prep, *parameters)
|
||||
is_rs = self._prep.execute()
|
||||
self.update_count = self._prep.getUpdateCount()
|
||||
if is_rs:
|
||||
self._rs = self._prep.getResultSet()
|
||||
self._meta = self._rs.getMetaData()
|
||||
# self._prep.getWarnings() ???
|
||||
|
||||
def executemany(self, operation, seq_of_parameters):
|
||||
self._close_last()
|
||||
self._prep = self._connection.jconn.prepareStatement(operation)
|
||||
for parameters in seq_of_parameters:
|
||||
self._set_stmt_parms(self._prep, *parameters)
|
||||
self._prep.addBatch()
|
||||
update_counts = self._prep.executeBatch()
|
||||
# self._prep.getWarnings() ???
|
||||
self.rowcount = sum(update_counts)
|
||||
|
||||
def fetchone(self):
|
||||
#raise if not rs
|
||||
if not self._rs.next():
|
||||
return None
|
||||
row = []
|
||||
for col in range(1, self._meta.getColumnCount() + 1):
|
||||
sqltype = self._meta.getColumnType(col)
|
||||
getter = getattr(self._rs, 'get%s' % METHOD_MAP[sqltype])
|
||||
v = getter(col)
|
||||
converter = TO_PY_MAP.get(sqltype)
|
||||
if converter:
|
||||
v = converter(v)
|
||||
row.append(v)
|
||||
return tuple(row)
|
||||
|
||||
def fetchmany(self, size=None):
|
||||
if size is None:
|
||||
size = self.arraysize
|
||||
self._rs.setFetchSize(size)
|
||||
rows = []
|
||||
row = None
|
||||
for i in xrange(size):
|
||||
row = self.fetchone()
|
||||
if row is None:
|
||||
break
|
||||
else:
|
||||
rows.append(row)
|
||||
# reset fetch size
|
||||
if row:
|
||||
self._rs.setFetchSize(0)
|
||||
return rows
|
||||
|
||||
def fetchall(self):
|
||||
rows = []
|
||||
while True:
|
||||
row = self.fetchone()
|
||||
if row is None:
|
||||
break
|
||||
else:
|
||||
rows.append(row)
|
||||
return rows
|
||||
|
||||
# optional nextset() unsupported
|
||||
|
||||
arraysize = 1
|
||||
|
||||
def setinputsizes(self, sizes):
|
||||
pass
|
||||
|
||||
def setoutputsize(self, size, column):
|
||||
pass
|
||||
|
||||
class JavaSqlTypes(object):
|
||||
# from java.sql.Types
|
||||
ARRAY=2003
|
||||
BIGINT=-5
|
||||
BINARY=-2
|
||||
BIT=-7
|
||||
BLOB=2004
|
||||
BOOLEAN=16
|
||||
CHAR=1
|
||||
CLOB=2005
|
||||
DATALINK=70
|
||||
DATE=91
|
||||
DECIMAL=3
|
||||
DISTINCT=2001
|
||||
DOUBLE=8
|
||||
FLOAT=6
|
||||
INTEGER=4
|
||||
JAVA_OBJECT=2000
|
||||
LONGVARBINARY=-4
|
||||
LONGVARCHAR=-1
|
||||
NULL=0
|
||||
NUMERIC=2
|
||||
OTHER=1111
|
||||
REAL=7
|
||||
REF=2006
|
||||
SMALLINT=5
|
||||
STRUCT=2002
|
||||
TIME=92
|
||||
TIMESTAMP=93
|
||||
TINYINT=-6
|
||||
VARBINARY=-3
|
||||
VARCHAR=12
|
||||
|
||||
METHOD_MAP = {
|
||||
JavaSqlTypes.ARRAY: 'Array',
|
||||
#AsciiStream
|
||||
JavaSqlTypes.NUMERIC: 'BigDecimal',
|
||||
JavaSqlTypes.DECIMAL: 'BigDecimal',
|
||||
#BinaryStream
|
||||
JavaSqlTypes.BLOB: 'Blob',
|
||||
JavaSqlTypes.BOOLEAN: 'Boolean',
|
||||
JavaSqlTypes.CHAR: 'String',
|
||||
JavaSqlTypes.BINARY: 'Bytes',
|
||||
#CharacterStream
|
||||
JavaSqlTypes.CLOB: 'Clob',
|
||||
JavaSqlTypes.DOUBLE: 'Double',
|
||||
JavaSqlTypes.DATE: 'Date',
|
||||
JavaSqlTypes.FLOAT: 'Float',
|
||||
JavaSqlTypes.INTEGER: 'Int',
|
||||
JavaSqlTypes.BIGINT: 'Long',
|
||||
JavaSqlTypes.SMALLINT: 'Short',
|
||||
JavaSqlTypes.VARCHAR: 'String',
|
||||
JavaSqlTypes.TIME: 'Time',
|
||||
JavaSqlTypes.TIMESTAMP: 'Timestamp',
|
||||
JavaSqlTypes.NULL: 'Null',
|
||||
}
|
||||
|
||||
TYPE_MAP = {
|
||||
int: JavaSqlTypes.INTEGER,
|
||||
long: JavaSqlTypes.BIGINT,
|
||||
float: JavaSqlTypes.DOUBLE,
|
||||
type(None): JavaSqlTypes.NULL,
|
||||
str: JavaSqlTypes.VARCHAR,
|
||||
bool: JavaSqlTypes.BOOLEAN,
|
||||
# buffer: JavaSqlTypes.BINARY,
|
||||
unicode: JavaSqlTypes.VARCHAR,
|
||||
}
|
||||
|
||||
def to_datetime(java_val):
|
||||
# d=datetime.datetime.strptime(timestmp.toString()[:-7], "%Y-%m-%d %H:%M:%S")
|
||||
# return d.replace(microsecond=int(str(timestmp.getNanos())[:6]))
|
||||
return java_val.toString()
|
||||
|
||||
def to_date(java_val):
|
||||
# d=datetime.datetime.strptime(timestmp.toString()[:-7], "%Y-%m-%d %H:%M:%S")
|
||||
# return d.replace(microsecond=int(str(timestmp.getNanos())[:6]))
|
||||
return java_val.toString()
|
||||
|
||||
def to_float(java_val):
|
||||
return java_val.doubleValue()
|
||||
|
||||
TO_PY_MAP = {
|
||||
JavaSqlTypes.TIMESTAMP: to_datetime,
|
||||
JavaSqlTypes.DATE: to_date,
|
||||
JavaSqlTypes.DECIMAL: to_float,
|
||||
JavaSqlTypes.NUMERIC: to_float,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
create table konto (
|
||||
"KONTO_ID" TIMESTAMP default CURRENT_TIMESTAMP not null,
|
||||
"KONTO_NR" INTEGER not null,
|
||||
"SALDO" DECIMAL default 0.0 not null,
|
||||
primary key ("KONTO_ID")
|
||||
);
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
insert into Konto values ('2009-09-10 14:15:22.123456', 18, 12.4);
|
||||
insert into Konto values ('2009-09-11 14:15:22.123456', 19, 12.9);
|
||||
@@ -0,0 +1,145 @@
|
||||
#-*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2010 Bastian Bowe
|
||||
#
|
||||
# This file is part of JayDeBeApi.
|
||||
# JayDeBeApi is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# JayDeBeApi is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with JayDeBeApi. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from unittest import TestCase
|
||||
import jaydebeapi
|
||||
import sys
|
||||
|
||||
this_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
jar_dir = os.path.abspath(os.path.join(this_dir, '..', '..',
|
||||
'build', 'lib'))
|
||||
create_sql = os.path.join(this_dir, 'data', 'create.sql')
|
||||
insert_sql = os.path.join(this_dir, 'data', 'insert.sql')
|
||||
|
||||
def is_jython():
|
||||
return sys.platform.lower().startswith('java')
|
||||
|
||||
class IntegrationTest(TestCase):
|
||||
|
||||
def sql_file(self, filename):
|
||||
f = open(filename, 'r')
|
||||
try:
|
||||
lines = f.readlines()
|
||||
finally:
|
||||
f.close()
|
||||
stmt = []
|
||||
stmts = []
|
||||
for i in lines:
|
||||
stmt.append(i)
|
||||
if ";" in i:
|
||||
stmts.append(" ".join(stmt))
|
||||
stmt = []
|
||||
cursor = self.conn.cursor()
|
||||
for i in stmts:
|
||||
cursor.execute(i)
|
||||
|
||||
def setup_jpype(self, jars):
|
||||
import jpype
|
||||
if not jpype.isJVMStarted():
|
||||
jvm_path = jpype.getDefaultJVMPath()
|
||||
#jvm_path = ('/usr/lib/jvm/java-6-openjdk'
|
||||
# '/jre/lib/i386/client/libjvm.so')
|
||||
args='-Djava.class.path=%s' % jars
|
||||
jpype.startJVM(jvm_path, args)
|
||||
if not jpype.isThreadAttachedToJVM():
|
||||
jpype.attachThreadToJVM()
|
||||
|
||||
def setUp(self):
|
||||
# TODO support more than one jar
|
||||
#jars='/usr/share/java/hsqldb.jar'
|
||||
jars=os.path.join(jar_dir, 'hsqldb.jar')
|
||||
#jars=jars_path(r'C:\Programme\DbVisualizer-4.3.5\jdbc')
|
||||
if is_jython():
|
||||
sys.path.append(jars)
|
||||
else:
|
||||
self.setup_jpype(jars)
|
||||
self.conn = jaydebeapi.connect('org.hsqldb.jdbcDriver',
|
||||
'jdbc:hsqldb:mem', 'SA', '')
|
||||
#conn = jaydebeapi.connect('com.ibm.db2.jcc.DB2Driver',
|
||||
# 'jdbc:db2://4.100.73.81:50000/db2t',
|
||||
# getpass.getuser(), getpass.getpass())
|
||||
self.sql_file(create_sql)
|
||||
self.sql_file(insert_sql)
|
||||
|
||||
def tearDown(self):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("drop table konto");
|
||||
self.conn.close()
|
||||
|
||||
def test_execute_and_fetch_no_data(self):
|
||||
cursor = self.conn.cursor()
|
||||
stmt = "select * from konto where konto_id is null"
|
||||
cursor.execute(stmt)
|
||||
assert [] == cursor.fetchall()
|
||||
|
||||
def test_execute_and_fetch(self):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("select * from konto")
|
||||
result = cursor.fetchall()
|
||||
assert [(u'2009-09-10 14:15:22.123456', 18, 12.4),
|
||||
(u'2009-09-11 14:15:22.123456', 19, 12.9)] == result
|
||||
|
||||
def test_execute_and_fetch_parameter(self):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("select * from konto where konto_nr = ?", 18)
|
||||
result = cursor.fetchall()
|
||||
assert [(u'2009-09-10 14:15:22.123456', 18, 12.4)] == result
|
||||
|
||||
def test_execute_and_fetchone(self):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("select * from konto order by konto_nr")
|
||||
result = cursor.fetchone()
|
||||
assert (u'2009-09-10 14:15:22.123456', 18, 12.4) == result
|
||||
|
||||
def test_execute_reset_description_without_execute_result(self):
|
||||
"""Excpect the descriptions property being reset when no query
|
||||
has been made via execute method.
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("select * from konto")
|
||||
assert None != cursor.description
|
||||
cursor.fetchone()
|
||||
cursor.execute("delete from konto")
|
||||
assert None == cursor.description
|
||||
|
||||
def test_execute_and_fetchone_after_end(self):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("select * from konto where konto_nr = ?", 18)
|
||||
cursor.fetchone()
|
||||
result = cursor.fetchone()
|
||||
assert None is result
|
||||
|
||||
def test_execute_and_fetchmany(self):
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("select * from konto order by konto_nr")
|
||||
result = cursor.fetchmany()
|
||||
assert [(u'2009-09-10 14:15:22.123456', 18, 12.4)] == result
|
||||
|
||||
def test_executemany(self):
|
||||
cursor = self.conn.cursor()
|
||||
stmt = "insert into Konto (KONTO_ID, KONTO_NR, SALDO) values (?, ?, ?)"
|
||||
parms = (
|
||||
( '2009-09-11 14:15:22.123450', 20, 13.1 ),
|
||||
( '2009-09-11 14:15:22.123451', 21, 13.2 ),
|
||||
( '2009-09-11 14:15:22.123452', 22, 13.3 ),
|
||||
)
|
||||
cursor.executemany(stmt, parms)
|
||||
assert cursor.rowcount == 3
|
||||
|
||||
Reference in New Issue
Block a user