|
5 | 5 | """ |
6 | 6 | import _ast |
7 | 7 | import atexit |
| 8 | +import datetime |
8 | 9 | import functools |
9 | 10 | import json |
10 | 11 | import optparse |
|
111 | 112 | ('unlink', ['ids']), |
112 | 113 | ('write', ['ids', 'vals']), |
113 | 114 | ] |
| 115 | +_sql_action_code = """\ |
| 116 | +sql_queries = env.context.get("__sql") or [] |
| 117 | +result = env.cr.connection.notices |
| 118 | +
|
| 119 | +if not env.is_system(): |
| 120 | + raise UserError("Not allowed") |
| 121 | +
|
| 122 | +for query in sql_queries: |
| 123 | + env.cr.execute(query) |
| 124 | + if not env.cr.description: |
| 125 | + result.append(env.cr.statusmessage) |
| 126 | + elif not env.cr.rowcount: |
| 127 | + result.append({c.name: () for c in env.cr.description}) |
| 128 | + else: |
| 129 | + columns = [c.name for c in env.cr.description] |
| 130 | + result.extend(dict(zip(columns, values)) for values in env.cr.fetchall()) |
| 131 | +
|
| 132 | +log(str({'queries': sql_queries, 'result': result})) |
| 133 | +result[:] = [] |
| 134 | +""" |
114 | 135 | colorize, color_comment, http_context = str, str, None |
115 | 136 |
|
116 | 137 | if os.getenv('ODOOLY_SSL_UNVERIFIED'): |
@@ -1097,6 +1118,32 @@ def generate_api_key(self): |
1097 | 1118 | assert res['res_model'] == "res.users.apikeys.show" |
1098 | 1119 | return self.set_api_key(res['context']['default_key']) |
1099 | 1120 |
|
| 1121 | + def _get_sql_action(self, _external_id="__odooly__.sql"): |
| 1122 | + act_model = self._get('ir.actions.server', False) |
| 1123 | + if not (action := act_model.get(_external_id)): |
| 1124 | + logg_model = self._get('ir.model', False).get('base.model_ir_logging') |
| 1125 | + values = {'name': 'SQL Execute', 'state': 'code', 'model_id': logg_model.id} |
| 1126 | + (action := act_model.create(values).ensure_one())._set_external_id(_external_id) |
| 1127 | + return action.with_context(lang=None) |
| 1128 | + |
| 1129 | + def sql(self, queries): |
| 1130 | + """Execute SQL commands on the PostgreSQL server.""" |
| 1131 | + qlist = [] |
| 1132 | + for query in queries.split(";"): |
| 1133 | + if any(li.split('--', 1)[0].strip() for li in query.splitlines()): |
| 1134 | + qlist.append(query) |
| 1135 | + if not qlist: |
| 1136 | + return None |
| 1137 | + |
| 1138 | + vals = {"name": f"SQL Execute - {datetime.datetime.now()}"} |
| 1139 | + if (sql_action := self._get_sql_action()).code != _sql_action_code: |
| 1140 | + vals["code"] = _sql_action_code |
| 1141 | + sql_action.write(vals) |
| 1142 | + sql_action.with_context(__sql=qlist).run() |
| 1143 | + |
| 1144 | + logg = self._get('ir.logging', False).get([f"func = {vals['name']}"]) |
| 1145 | + return eval(logg.message, {"datetime": datetime}) if logg else None |
| 1146 | + |
1100 | 1147 |
|
1101 | 1148 | class Client: |
1102 | 1149 | """Connection to an Odoo instance. |
|
0 commit comments