You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
6.3 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2011 Daniel Reis
  3. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
  4. import os
  5. import logging
  6. import psycopg2
  7. from odoo import models, fields, api, _
  8. from odoo.exceptions import Warning as UserError
  9. import odoo.tools as tools
  10. _logger = logging.getLogger(__name__)
  11. CONNECTORS = []
  12. try:
  13. import sqlalchemy
  14. CONNECTORS.append(('sqlite', 'SQLite'))
  15. try:
  16. import pymssql
  17. CONNECTORS.append(('mssql', 'Microsoft SQL Server'))
  18. assert pymssql
  19. except (ImportError, AssertionError):
  20. _logger.info('MS SQL Server not available. Please install "pymssql"\
  21. python package.')
  22. try:
  23. import MySQLdb
  24. CONNECTORS.append(('mysql', 'MySQL'))
  25. assert MySQLdb
  26. except (ImportError, AssertionError):
  27. _logger.info('MySQL not available. Please install "mysqldb"\
  28. python package.')
  29. except:
  30. _logger.info('SQL Alchemy not available. Please install "slqalchemy"\
  31. python package.')
  32. try:
  33. import pyodbc
  34. CONNECTORS.append(('pyodbc', 'ODBC'))
  35. except:
  36. _logger.info('ODBC libraries not available. Please install "unixodbc"\
  37. and "python-pyodbc" packages.')
  38. try:
  39. import cx_Oracle
  40. CONNECTORS.append(('cx_Oracle', 'Oracle'))
  41. except:
  42. _logger.info('Oracle libraries not available. Please install "cx_Oracle"\
  43. python package.')
  44. try:
  45. import fdb
  46. CONNECTORS.append(('fdb', 'Firebird'))
  47. except:
  48. _logger.info('Firebird libraries not available. Please install "fdb"\
  49. python package.')
  50. CONNECTORS.append(('postgresql', 'PostgreSQL'))
  51. class BaseExternalDbsource(models.Model):
  52. _name = "base.external.dbsource"
  53. _description = 'External Database Sources'
  54. name = fields.Char('Datasource name', required=True, size=64)
  55. conn_string = fields.Text('Connection string', help="""
  56. Sample connection strings:
  57. - Microsoft SQL Server:
  58. mssql+pymssql://username:%s@server:port/dbname?charset=utf8
  59. - MySQL: mysql://user:%s@server:port/dbname
  60. - ODBC: DRIVER={FreeTDS};SERVER=server.address;Database=mydb;UID=sa
  61. - ORACLE: username/%s@//server.address:port/instance
  62. - FireBird: host=localhost;database=mydatabase.gdb;user=sysdba;password=%s;
  63. port=3050;charset=utf8
  64. - PostgreSQL:
  65. dbname='template1' user='dbuser' host='localhost' port='5432' \
  66. password=%s
  67. - SQLite: sqlite:///test.db
  68. """)
  69. password = fields.Char('Password', size=40)
  70. connector = fields.Selection(CONNECTORS, 'Connector', required=True,
  71. help="If a connector is missing from the\
  72. list, check the server log to confirm\
  73. that the required components were\
  74. detected.")
  75. @api.multi
  76. def conn_open(self):
  77. """The connection is open here."""
  78. self.ensure_one()
  79. # Get dbsource record
  80. # Build the full connection string
  81. connStr = self.conn_string
  82. if self.password:
  83. if '%s' not in self.conn_string:
  84. connStr += ';PWD=%s'
  85. connStr = connStr % self.password
  86. # Try to connect
  87. if self.connector == 'cx_Oracle':
  88. os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.UTF8'
  89. conn = cx_Oracle.connect(connStr)
  90. elif self.connector == 'pyodbc':
  91. conn = pyodbc.connect(connStr)
  92. elif self.connector in ('sqlite', 'mysql', 'mssql'):
  93. conn = sqlalchemy.create_engine(connStr).connect()
  94. elif self.connector == 'fdb':
  95. kwargs = dict([x.split('=') for x in connStr.split(';')])
  96. conn = fdb.connect(**kwargs)
  97. elif self.connector == 'postgresql':
  98. conn = psycopg2.connect(connStr)
  99. return conn
  100. @api.multi
  101. def execute(self, sqlquery, sqlparams=None, metadata=False,
  102. context=None):
  103. """Executes SQL and returns a list of rows.
  104. "sqlparams" can be a dict of values, that can be referenced in
  105. the SQL statement using "%(key)s" or, in the case of Oracle,
  106. ":key".
  107. Example:
  108. sqlquery = "select * from mytable where city = %(city)s and
  109. date > %(dt)s"
  110. params = {'city': 'Lisbon',
  111. 'dt': datetime.datetime(2000, 12, 31)}
  112. If metadata=True, it will instead return a dict containing the
  113. rows list and the columns list, in the format:
  114. { 'cols': [ 'col_a', 'col_b', ...]
  115. , 'rows': [ (a0, b0, ...), (a1, b1, ...), ...] }
  116. """
  117. rows, cols = list(), list()
  118. for obj in self:
  119. conn = obj.conn_open()
  120. if obj.connector in ["sqlite", "mysql", "mssql"]:
  121. # using sqlalchemy
  122. cur = conn.execute(sqlquery, sqlparams)
  123. if metadata:
  124. cols = cur.keys()
  125. rows = [r for r in cur]
  126. elif obj.connector in ["fdb"]:
  127. # using other db connectors
  128. cur = conn.cursor()
  129. for key in sqlparams:
  130. sqlquery = sqlquery.replace('%%(%s)s' % key,
  131. str(sqlparams[key]))
  132. cur.execute(sqlquery)
  133. rows = cur.fetchall()
  134. else:
  135. # using other db connectors
  136. cur = conn.cursor()
  137. cur.execute(sqlquery, sqlparams)
  138. if metadata:
  139. cols = [d[0] for d in cur.description]
  140. rows = cur.fetchall()
  141. conn.close()
  142. if metadata:
  143. return{'cols': cols, 'rows': rows}
  144. else:
  145. return rows
  146. @api.multi
  147. def connection_test(self):
  148. """Test of connection."""
  149. self.ensure_one()
  150. conn = False
  151. try:
  152. conn = self.conn_open()
  153. except Exception as e:
  154. raise UserError(_("Connection test failed: \
  155. Here is what we got instead:\n %s") % tools.ustr(e))
  156. finally:
  157. if conn:
  158. conn.close()
  159. # TODO: if OK a (wizard) message box should be displayed
  160. raise UserError(_("Connection test succeeded: \
  161. Everything seems properly set up!"))