From 4b75084980631e548a9af7fa69c049f9069ba01b Mon Sep 17 00:00:00 2001 From: Michell Stuttgart Date: Wed, 30 Nov 2016 15:17:32 -0200 Subject: [PATCH] [10.0] Add Firebird database support to base_external_dbsource (#623) --- base_external_dbsource/README.rst | 10 ++-- base_external_dbsource/__manifest__.py | 2 +- .../models/base_external_dbsource.py | 56 +++++++++++++------ .../tests/test_create_dbsource.py | 8 +++ 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/base_external_dbsource/README.rst b/base_external_dbsource/README.rst index 79760c960..a916f045b 100644 --- a/base_external_dbsource/README.rst +++ b/base_external_dbsource/README.rst @@ -6,7 +6,7 @@ External Database Sources ========================= -This module allows you to define connections to foreign databases using ODBC, +This module allows you to define connections to foreign databases using ODBC, Firebird, Oracle Client or SQLAlchemy. Installation @@ -22,8 +22,9 @@ Database sources can be configured in Settings > Configuration -> Data sources. Depending on the database, you need: * to install unixodbc and python-pyodbc packages to use ODBC connections. -* to install FreeTDS driver (tdsodbc package) and configure it through ODBC toconnect to Microsoft SQL Server. +* to install FreeTDS driver (tdsodbc package) and configure it through ODBC to connect to Microsoft SQL Server. * to install and configure Oracle Instant Client and cx_Oracle python library to connect to Oracle. +* to install fdb package to connect in Firebird. Usage @@ -34,8 +35,8 @@ To use this module: * Go to Settings > Database Structure > Database Sources * Click on Create to enter the following information: -* Datasource name  -* Pasword +* Data source name  +* Password * Connector: Choose the database to which you want to connect * Connection string : Specify how to connect to database @@ -65,6 +66,7 @@ Contributors * Daniel Reis * Maxime Chambreuil * Gervais Naoussi +* Michell Stuttgart Maintainer ---------- diff --git a/base_external_dbsource/__manifest__.py b/base_external_dbsource/__manifest__.py index 24db6e35a..3ef362432 100644 --- a/base_external_dbsource/__manifest__.py +++ b/base_external_dbsource/__manifest__.py @@ -4,7 +4,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': 'External Database Sources', - 'version': '10.0.1.0.0', + 'version': '10.0.1.0.1', 'category': 'Tools', 'author': "Daniel Reis,Odoo Community Association (OCA)", 'website': 'https://github.com/OCA/server-tools', diff --git a/base_external_dbsource/models/base_external_dbsource.py b/base_external_dbsource/models/base_external_dbsource.py index 3fe2718fb..79a581689 100644 --- a/base_external_dbsource/models/base_external_dbsource.py +++ b/base_external_dbsource/models/base_external_dbsource.py @@ -25,6 +25,7 @@ import psycopg2 from odoo import models, fields, api, _ from odoo.exceptions import Warning as UserError import odoo.tools as tools + _logger = logging.getLogger(__name__) CONNECTORS = [] @@ -63,13 +64,23 @@ except: _logger.info('Oracle libraries not available. Please install "cx_Oracle"\ python package.') +try: + import fdb + CONNECTORS.append(('fdb', 'Firebird')) +except: + _logger.info('Firebird libraries not available. Please install "fdb"\ + python package.') + CONNECTORS.append(('postgresql', 'PostgreSQL')) class BaseExternalDbsource(models.Model): + _name = "base.external.dbsource" _description = 'External Database Sources' + name = fields.Char('Datasource name', required=True, size=64) + conn_string = fields.Text('Connection string', help=""" Sample connection strings: - Microsoft SQL Server: @@ -77,12 +88,16 @@ class BaseExternalDbsource(models.Model): - MySQL: mysql://user:%s@server:port/dbname - ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa - ORACLE: username/%s@//server.address:port/instance + - FireBird: host=localhost;database=mydatabase.gdb;user=sysdba;password=%s; + port=3050;charset=utf8 - 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\ @@ -95,13 +110,13 @@ class BaseExternalDbsource(models.Model): self.ensure_one() # Get dbsource record - # data = self.browse(cr, uid, id1) # Build the full connection string connStr = self.conn_string if self.password: if '%s' not in self.conn_string: connStr += ';PWD=%s' connStr = connStr % self.password + # Try to connect if self.connector == 'cx_Oracle': os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.UTF8' @@ -110,6 +125,9 @@ class BaseExternalDbsource(models.Model): conn = pyodbc.connect(connStr) elif self.connector in ('sqlite', 'mysql', 'mssql'): conn = sqlalchemy.create_engine(connStr).connect() + elif self.connector == 'fdb': + kwargs = dict([x.split('=') for x in connStr.split(';')]) + conn = fdb.connect(**kwargs) elif self.connector == 'postgresql': conn = psycopg2.connect(connStr) @@ -134,7 +152,7 @@ class BaseExternalDbsource(models.Model): { 'cols': [ 'col_a', 'col_b', ...] , 'rows': [ (a0, b0, ...), (a1, b1, ...), ...] } """ - # data = self.browse(cr, uid, ids) + rows, cols = list(), list() for obj in self: conn = obj.conn_open() @@ -144,6 +162,16 @@ class BaseExternalDbsource(models.Model): if metadata: cols = cur.keys() rows = [r for r in cur] + + elif obj.connector in ["fdb"]: + # using other db connectors + cur = conn.cursor() + for key in sqlparams: + sqlquery = sqlquery.replace('%%(%s)s' % key, + str(sqlparams[key])) + + cur.execute(sqlquery) + rows = cur.fetchall() else: # using other db connectors cur = conn.cursor() @@ -160,21 +188,17 @@ class BaseExternalDbsource(models.Model): @api.multi def connection_test(self): """Test of connection.""" + self.ensure_one() + conn = False + try: + conn = self.conn_open() + except Exception as e: + raise UserError(_("Connection test failed: \ + Here is what we got instead:\n %s") % tools.ustr(e)) + finally: + if conn: + conn.close() - for obj in self: - conn = False - try: - conn = self.conn_open() - except Exception as e: - raise UserError(_("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 UserError(_("Connection test succeeded: \ Everything seems properly set up!")) diff --git a/base_external_dbsource/tests/test_create_dbsource.py b/base_external_dbsource/tests/test_create_dbsource.py index 5b64f606e..7f0807d9b 100644 --- a/base_external_dbsource/tests/test_create_dbsource.py +++ b/base_external_dbsource/tests/test_create_dbsource.py @@ -56,3 +56,11 @@ class TestCreateDbsource(common.TransactionCase): except ValueError as e: logging.warning("Log = " + str(e)) self.assertTrue(u'Wrong value for' in str(e)) + + # Connection to firebird + try: + dbsource.connector = "fdb" + dbsource.connection_test() + except Exception as e: + logging.warning("Log = " + str(e)) + self.assertTrue(u'Wrong value for' in str(e))