mirror of
https://github.com/OCA/reporting-engine.git
synced 2025-02-16 16:30:38 +02:00
[IMP] Make possible to make sql queries on an external database
This commit is contained in:
@@ -1 +1,2 @@
|
||||
from . import models
|
||||
from . import sql_db
|
||||
|
||||
@@ -12,8 +12,10 @@ from io import BytesIO
|
||||
from psycopg2 import ProgrammingError
|
||||
from psycopg2.sql import SQL
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo import _, api, fields, models, tools
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
from ..sql_db import get_external_cursor
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -96,6 +98,26 @@ class SQLRequestMixin(models.AbstractModel):
|
||||
column2="user_id",
|
||||
default=_default_user_ids,
|
||||
)
|
||||
use_external_database = fields.Boolean(
|
||||
help=(
|
||||
"If filled, the query will be executed against an external "
|
||||
"database, configured in Odoo main configuration file. "
|
||||
)
|
||||
)
|
||||
|
||||
@api.constrains("use_external_database")
|
||||
def check_external_config(self):
|
||||
external_db_records = self.filtered(lambda rec: rec.use_external_database)
|
||||
if external_db_records:
|
||||
external_db_name = tools.config.get("external_db_name")
|
||||
if not external_db_name:
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You can't use an external database as there are no such "
|
||||
"configuration about this. Please contact your Odoo administrator"
|
||||
" to solve this issue."
|
||||
)
|
||||
)
|
||||
|
||||
has_group_changed = fields.Boolean(
|
||||
copy=False,
|
||||
@@ -202,42 +224,54 @@ class SQLRequestMixin(models.AbstractModel):
|
||||
else:
|
||||
raise UserError(_("Unimplemented mode : '%s'") % mode)
|
||||
|
||||
query_cr = self._get_cr_for_query()
|
||||
|
||||
if rollback:
|
||||
rollback_name = self._create_savepoint()
|
||||
rollback_name = self._create_savepoint(query_cr)
|
||||
try:
|
||||
if mode == "stdout":
|
||||
output = BytesIO()
|
||||
self.env.cr.copy_expert(query, output)
|
||||
query_cr.copy_expert(query, output)
|
||||
res = base64.b64encode(output.getvalue())
|
||||
output.close()
|
||||
else:
|
||||
self.env.cr.execute(query)
|
||||
query_cr.execute(query)
|
||||
if mode == "fetchall":
|
||||
res = self.env.cr.fetchall()
|
||||
res = query_cr.fetchall()
|
||||
if header:
|
||||
colnames = [desc[0] for desc in self.env.cr.description]
|
||||
res.insert(0, colnames)
|
||||
elif mode == "fetchone":
|
||||
res = self.env.cr.fetchone()
|
||||
res = query_cr.fetchone()
|
||||
finally:
|
||||
self._rollback_savepoint(rollback_name)
|
||||
self._rollback_savepoint(rollback_name, query_cr)
|
||||
|
||||
return res
|
||||
|
||||
# Private Section
|
||||
def _get_cr_for_query(self):
|
||||
self.ensure_one()
|
||||
if self.use_external_database:
|
||||
return get_external_cursor()
|
||||
else:
|
||||
return self.env.cr
|
||||
|
||||
@api.model
|
||||
def _create_savepoint(self):
|
||||
def _create_savepoint(self, cr):
|
||||
rollback_name = "{}_{}".format(self._name.replace(".", "_"), uuid.uuid1().hex)
|
||||
# pylint: disable=sql-injection
|
||||
req = "SAVEPOINT %s" % (rollback_name)
|
||||
self.env.cr.execute(req)
|
||||
cr.execute(req)
|
||||
return rollback_name
|
||||
|
||||
@api.model
|
||||
def _rollback_savepoint(self, rollback_name):
|
||||
def _rollback_savepoint(self, rollback_name, cr):
|
||||
# pylint: disable=sql-injection
|
||||
req = "ROLLBACK TO SAVEPOINT %s" % (rollback_name)
|
||||
self.env.cr.execute(req)
|
||||
cr.execute(req)
|
||||
# close external database cursor
|
||||
if self.env.cr != cr:
|
||||
cr.close()
|
||||
|
||||
@api.model
|
||||
def _check_materialized_view_available(self):
|
||||
|
||||
6
sql_request_abstract/readme/CONFIGURE.rst
Normal file
6
sql_request_abstract/readme/CONFIGURE.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
To configure the use of an external database, you need to edit the main configuration file of your instance and add the external database configuration with following keys :
|
||||
* external_db_user
|
||||
* external_db_password
|
||||
* external_db_name
|
||||
* external_db_host
|
||||
* external_db_port
|
||||
22
sql_request_abstract/sql_db.py
Normal file
22
sql_request_abstract/sql_db.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import tools
|
||||
from odoo.sql_db import Connection, ConnectionPool, _Pool # noqa
|
||||
|
||||
|
||||
def connection_info_for_external_database():
|
||||
db_name = tools.config.get("external_db_name")
|
||||
connection_info = {"database": db_name}
|
||||
for p in ("host", "port", "user", "password"):
|
||||
cfg = tools.config.get("external_db_" + p)
|
||||
if cfg:
|
||||
connection_info[p] = cfg
|
||||
return db_name, connection_info
|
||||
|
||||
|
||||
def get_external_cursor():
|
||||
global _Pool
|
||||
if _Pool is None:
|
||||
_Pool = ConnectionPool(int(tools.config["db_maxconn"]))
|
||||
db, info = connection_info_for_external_database()
|
||||
return Connection(_Pool, db, info).cursor()
|
||||
Reference in New Issue
Block a user