Maxime Chambreuil
11 years ago
6 changed files with 244 additions and 223 deletions
-
2base_external_dbsource/__init__.py
-
9base_external_dbsource/__openerp__.py
-
339base_external_dbsource/base_external_dbsource.py
-
2import_odbc/__init__.py
-
13import_odbc/__openerp__.py
-
102import_odbc/import_odbc.py
@ -1,159 +1,180 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
############################################################################## |
|
||||
# |
|
||||
# Daniel Reis |
|
||||
# 2011 |
|
||||
# |
|
||||
# This program is free software: you can redistribute it and/or modify |
|
||||
# it under the terms of the GNU Affero General Public License as |
|
||||
# published by the Free Software Foundation, either version 3 of the |
|
||||
# License, or (at your option) any later version. |
|
||||
# |
|
||||
# This program 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 Affero General Public License for more details. |
|
||||
# |
|
||||
# You should have received a copy of the GNU Affero General Public License |
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
||||
# |
|
||||
############################################################################## |
|
||||
|
|
||||
import os |
|
||||
from osv import fields, osv |
|
||||
from openerp.tools.translate import _ |
|
||||
import openerp.tools as tools |
|
||||
import logging |
|
||||
_logger = logging.getLogger(__name__) |
|
||||
|
|
||||
CONNECTORS = [] |
|
||||
|
|
||||
try: |
|
||||
import sqlalchemy |
|
||||
import pymssql |
|
||||
CONNECTORS.append( ('mssql', 'Microsoft SQL Server') ) |
|
||||
except: |
|
||||
_logger.info('MS SQL Server not available. Please install "slqalchemy" and "pymssql" python package.') |
|
||||
|
|
||||
try: |
|
||||
import sqlalchemy |
|
||||
import MySQLdb |
|
||||
CONNECTORS.append( ('mysql', 'MySQL') ) |
|
||||
except: |
|
||||
_logger.info('MySQL not available. Please install "slqalchemy" and "mysqldb" python package.') |
|
||||
|
|
||||
try: |
|
||||
import pyodbc |
|
||||
CONNECTORS.append( ('pyodbc', 'ODBC') ) |
|
||||
except: |
|
||||
_logger.info('ODBC libraries not available. Please install "unixodbc" and "python-pyodbc" packages.') |
|
||||
|
|
||||
try: |
|
||||
import cx_Oracle |
|
||||
CONNECTORS.append( ('cx_Oracle', 'Oracle') ) |
|
||||
except: |
|
||||
_logger.info('Oracle libraries not available. Please install "cx_Oracle" python package.') |
|
||||
|
|
||||
import psycopg2 |
|
||||
CONNECTORS.append( ('postgresql', 'PostgreSQL') ) |
|
||||
|
|
||||
try: |
|
||||
import sqlalchemy |
|
||||
CONNECTORS.append( ('sqlite', 'SQLite') ) |
|
||||
except: |
|
||||
_logger.info('SQLAlchemy not available. Please install "slqalchemy" python package.') |
|
||||
|
|
||||
class base_external_dbsource(osv.osv): |
|
||||
_name = "base.external.dbsource" |
|
||||
_description = 'External Database Sources' |
|
||||
_columns = { |
|
||||
'name': fields.char('Datasource name', required=True, size=64), |
|
||||
'conn_string': fields.text('Connection string', help="""\ |
|
||||
Sample connection strings: |
|
||||
- Microsoft SQL Server: mssql+pymssql://username:%s@server:port/dbname?charset=utf8 |
|
||||
- MySQL: mysql://user:%s@server:port/dbname |
|
||||
- ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa |
|
||||
- ORACLE: username/%s@//server.address:port/instance |
|
||||
- PostgreSQL: dbname='template1' user='dbuser' host='localhost' port='5432' password=%s |
|
||||
- SQLite: sqlite:///test.db |
|
||||
"""), |
|
||||
'password': fields.char('Password' , size=40), |
|
||||
'connector': fields.selection(CONNECTORS, 'Connector', required=True, |
|
||||
help = "If a connector is missing from the list, check the " \ |
|
||||
+ "server log to confirm that the required componentes were detected."), |
|
||||
} |
|
||||
|
|
||||
def conn_open(self, cr, uid, id1): |
|
||||
#Get dbsource record |
|
||||
data = self.browse(cr, uid, id1) |
|
||||
#Build the full connection string |
|
||||
connStr = data.conn_string |
|
||||
if data.password: |
|
||||
if '%s' not in data.conn_string: |
|
||||
connStr += ';PWD=%s' |
|
||||
connStr = connStr % data.password |
|
||||
#Try to connect |
|
||||
if data.connector == 'cx_Oracle': |
|
||||
os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.UTF8' |
|
||||
conn = cx_Oracle.connect(connStr) |
|
||||
elif data.connector == 'pyodbc': |
|
||||
conn = pyodbc.connect(connStr) |
|
||||
elif data.connector in ('sqlite','mysql','mssql'): |
|
||||
conn = sqlalchemy.create_engine(connStr).connect() |
|
||||
elif data.connector == 'postgresql': |
|
||||
conn = psycopg2.connect(connStr) |
|
||||
|
|
||||
return conn |
|
||||
|
|
||||
def execute(self, cr, uid, ids, sqlquery, sqlparams=None, metadata=False, context=None): |
|
||||
"""Executes SQL and returns a list of rows. |
|
||||
|
|
||||
"sqlparams" can be a dict of values, that can be referenced in the SQL statement |
|
||||
using "%(key)s" or, in the case of Oracle, ":key". |
|
||||
Example: |
|
||||
sqlquery = "select * from mytable where city = %(city)s and date > %(dt)s" |
|
||||
params = {'city': 'Lisbon', 'dt': datetime.datetime(2000, 12, 31)} |
|
||||
|
|
||||
If metadata=True, it will instead return a dict containing the rows list and the columns list, |
|
||||
in the format: |
|
||||
{ 'cols': [ 'col_a', 'col_b', ...] |
|
||||
, 'rows': [ (a0, b0, ...), (a1, b1, ...), ...] } |
|
||||
""" |
|
||||
data = self.browse(cr, uid, ids) |
|
||||
rows, cols = list(), list() |
|
||||
for obj in data: |
|
||||
conn = self.conn_open(cr, uid, obj.id) |
|
||||
if obj.connector in ["sqlite","mysql","mssql"]: |
|
||||
#using sqlalchemy |
|
||||
cur = conn.execute(sqlquery, sqlparams) |
|
||||
if metadata: cols = cur.keys() |
|
||||
rows = [r for r in cur] |
|
||||
else: |
|
||||
#using other db connectors |
|
||||
cur = conn.cursor() |
|
||||
cur.execute(sqlquery, sqlparams) |
|
||||
if metadata: cols = [d[0] for d in cur.description] |
|
||||
rows = cur.fetchall() |
|
||||
conn.close() |
|
||||
if metadata: |
|
||||
return{'cols': cols, 'rows': rows} |
|
||||
else: |
|
||||
return rows |
|
||||
|
|
||||
def connection_test(self, cr, uid, ids, context=None): |
|
||||
for obj in self.browse(cr, uid, ids, context): |
|
||||
conn = False |
|
||||
try: |
|
||||
conn = self.conn_open(cr, uid, obj.id) |
|
||||
except Exception, e: |
|
||||
raise osv.except_osv(_("Connection test failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e)) |
|
||||
finally: |
|
||||
try: |
|
||||
if conn: conn.close() |
|
||||
except Exception: |
|
||||
# ignored, just a consequence of the previous exception |
|
||||
pass |
|
||||
#TODO: if OK a (wizard) message box should be displayed |
|
||||
raise osv.except_osv(_("Connection test succeeded!"), _("Everything seems properly set up!")) |
|
||||
|
|
||||
base_external_dbsource() |
|
||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################## |
||||
|
# |
||||
|
# Daniel Reis |
||||
|
# 2011 |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program 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 Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################## |
||||
|
|
||||
|
import os |
||||
|
import logging |
||||
|
from openerp.osv import orm, fields |
||||
|
from openerp.tools.translate import _ |
||||
|
import openerp.tools as tools |
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
CONNECTORS = [] |
||||
|
|
||||
|
try: |
||||
|
import sqlalchemy |
||||
|
import pymssql |
||||
|
CONNECTORS.append(('mssql', 'Microsoft SQL Server')) |
||||
|
except: |
||||
|
_logger.info('MS SQL Server not available. Please install "slqalchemy"\ |
||||
|
and "pymssql" python package.') |
||||
|
|
||||
|
try: |
||||
|
import sqlalchemy |
||||
|
import MySQLdb |
||||
|
CONNECTORS.append(('mysql', 'MySQL')) |
||||
|
except: |
||||
|
_logger.info('MySQL not available. Please install "slqalchemy" and\ |
||||
|
"mysqldb" python package.') |
||||
|
|
||||
|
try: |
||||
|
import pyodbc |
||||
|
CONNECTORS.append(('pyodbc', 'ODBC')) |
||||
|
except: |
||||
|
_logger.info('ODBC libraries not available. Please install "unixodbc"\ |
||||
|
and "python-pyodbc" packages.') |
||||
|
|
||||
|
try: |
||||
|
import cx_Oracle |
||||
|
CONNECTORS.append(('cx_Oracle', 'Oracle')) |
||||
|
except: |
||||
|
_logger.info('Oracle libraries not available. Please install "cx_Oracle"\ |
||||
|
python package.') |
||||
|
|
||||
|
import psycopg2 |
||||
|
CONNECTORS.append(('postgresql', 'PostgreSQL')) |
||||
|
|
||||
|
try: |
||||
|
import sqlalchemy |
||||
|
CONNECTORS.append(('sqlite', 'SQLite')) |
||||
|
except: |
||||
|
_logger.info('SQLAlchemy not available. Please install "slqalchemy" python\ |
||||
|
package.') |
||||
|
|
||||
|
|
||||
|
class base_external_dbsource(orm.Model): |
||||
|
_name = "base.external.dbsource" |
||||
|
_description = 'External Database Sources' |
||||
|
_columns = { |
||||
|
'name': fields.char('Datasource name', required=True, size=64), |
||||
|
'conn_string': fields.text('Connection string', help=""" |
||||
|
Sample connection strings: |
||||
|
- Microsoft SQL Server: |
||||
|
mssql+pymssql://username:%s@server:port/dbname?charset=utf8 |
||||
|
- MySQL: mysql://user:%s@server:port/dbname |
||||
|
- ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa |
||||
|
- ORACLE: username/%s@//server.address:port/instance |
||||
|
- PostgreSQL: |
||||
|
dbname='template1' user='dbuser' host='localhost' port='5432' password=%s |
||||
|
- SQLite: sqlite:///test.db |
||||
|
"""), |
||||
|
'password': fields.char('Password', size=40), |
||||
|
'connector': fields.selection(CONNECTORS, 'Connector', |
||||
|
required=True, |
||||
|
help="If a connector is missing from the\ |
||||
|
list, check the server log to confirm\ |
||||
|
that the required components were\ |
||||
|
detected."), |
||||
|
} |
||||
|
|
||||
|
def conn_open(self, cr, uid, id1): |
||||
|
#Get dbsource record |
||||
|
data = self.browse(cr, uid, id1) |
||||
|
#Build the full connection string |
||||
|
connStr = data.conn_string |
||||
|
if data.password: |
||||
|
if '%s' not in data.conn_string: |
||||
|
connStr += ';PWD=%s' |
||||
|
connStr = connStr % data.password |
||||
|
#Try to connect |
||||
|
if data.connector == 'cx_Oracle': |
||||
|
os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.UTF8' |
||||
|
conn = cx_Oracle.connect(connStr) |
||||
|
elif data.connector == 'pyodbc': |
||||
|
conn = pyodbc.connect(connStr) |
||||
|
elif data.connector in ('sqlite', 'mysql', 'mssql'): |
||||
|
conn = sqlalchemy.create_engine(connStr).connect() |
||||
|
elif data.connector == 'postgresql': |
||||
|
conn = psycopg2.connect(connStr) |
||||
|
|
||||
|
return conn |
||||
|
|
||||
|
def execute(self, cr, uid, ids, sqlquery, sqlparams=None, metadata=False, |
||||
|
context=None): |
||||
|
"""Executes SQL and returns a list of rows. |
||||
|
|
||||
|
"sqlparams" can be a dict of values, that can be referenced in |
||||
|
the SQL statement using "%(key)s" or, in the case of Oracle, |
||||
|
":key". |
||||
|
Example: |
||||
|
sqlquery = "select * from mytable where city = %(city)s and |
||||
|
date > %(dt)s" |
||||
|
params = {'city': 'Lisbon', |
||||
|
'dt': datetime.datetime(2000, 12, 31)} |
||||
|
|
||||
|
If metadata=True, it will instead return a dict containing the |
||||
|
rows list and the columns list, in the format: |
||||
|
{ 'cols': [ 'col_a', 'col_b', ...] |
||||
|
, 'rows': [ (a0, b0, ...), (a1, b1, ...), ...] } |
||||
|
""" |
||||
|
data = self.browse(cr, uid, ids) |
||||
|
rows, cols = list(), list() |
||||
|
for obj in data: |
||||
|
conn = self.conn_open(cr, uid, obj.id) |
||||
|
if obj.connector in ["sqlite", "mysql", "mssql"]: |
||||
|
#using sqlalchemy |
||||
|
cur = conn.execute(sqlquery, sqlparams) |
||||
|
if metadata: |
||||
|
cols = cur.keys() |
||||
|
rows = [r for r in cur] |
||||
|
else: |
||||
|
#using other db connectors |
||||
|
cur = conn.cursor() |
||||
|
cur.execute(sqlquery, sqlparams) |
||||
|
if metadata: |
||||
|
cols = [d[0] for d in cur.description] |
||||
|
rows = cur.fetchall() |
||||
|
conn.close() |
||||
|
if metadata: |
||||
|
return{'cols': cols, 'rows': rows} |
||||
|
else: |
||||
|
return rows |
||||
|
|
||||
|
def connection_test(self, cr, uid, ids, context=None): |
||||
|
for obj in self.browse(cr, uid, ids, context): |
||||
|
conn = False |
||||
|
try: |
||||
|
conn = self.conn_open(cr, uid, obj.id) |
||||
|
except Exception, e: |
||||
|
raise osv.except_osv(_("Connection test failed!"), |
||||
|
_("Here is what we got instead:\n %s") |
||||
|
% tools.ustr(e)) |
||||
|
finally: |
||||
|
try: |
||||
|
if conn: |
||||
|
conn.close() |
||||
|
except Exception: |
||||
|
# ignored, just a consequence of the previous exception |
||||
|
pass |
||||
|
#TODO: if OK a (wizard) message box should be displayed |
||||
|
raise osv.except_osv(_("Connection test succeeded!"), |
||||
|
_("Everything seems properly set up!")) |
||||
|
|
||||
|
#EOF |
Write
Preview
Loading…
Cancel
Save
Reference in new issue