|
14 | 14 | import secrets |
15 | 15 | from urllib.parse import unquote |
16 | 16 | from threading import Lock |
| 17 | +from io import BytesIO |
17 | 18 | import threading |
18 | 19 | import math |
19 | 20 |
|
|
23 | 24 |
|
24 | 25 | from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD |
25 | 26 | from werkzeug.user_agent import UserAgent |
26 | | -from flask import Response, url_for, render_template, session, current_app |
| 27 | +from flask import Response, url_for, render_template, session, current_app, \ |
| 28 | + send_file |
27 | 29 | from flask import request |
28 | 30 | from flask_babel import gettext |
29 | 31 | from pgadmin.tools.sqleditor.utils.query_tool_connection_check \ |
|
70 | 72 | from pgadmin.browser.server_groups.servers.utils import \ |
71 | 73 | convert_connection_parameter, get_db_disp_restriction |
72 | 74 | from pgadmin.misc.workspaces import check_and_delete_adhoc_server |
| 75 | +from pgadmin.utils.driver.psycopg3.typecast import \ |
| 76 | + register_binary_data_typecasters |
73 | 77 |
|
74 | 78 | MODULE_NAME = 'sqleditor' |
75 | 79 | TRANSACTION_STATUS_CHECK_FAILED = gettext("Transaction status check failed.") |
@@ -147,6 +151,7 @@ def get_exposed_url_endpoints(self): |
147 | 151 | 'sqleditor.server_cursor', |
148 | 152 | 'sqleditor.nlq_chat_stream', |
149 | 153 | 'sqleditor.explain_analyze_stream', |
| 154 | + 'sqleditor.download_binary_data', |
150 | 155 | ] |
151 | 156 |
|
152 | 157 | def on_logout(self): |
@@ -2182,6 +2187,49 @@ def start_query_download_tool(trans_id): |
2182 | 2187 | return internal_server_error(errormsg=err_msg) |
2183 | 2188 |
|
2184 | 2189 |
|
| 2190 | +@blueprint.route( |
| 2191 | + '/download_binary_data/<int:trans_id>', |
| 2192 | + methods=["POST"], endpoint='download_binary_data' |
| 2193 | +) |
| 2194 | +@pga_login_required |
| 2195 | +def download_binary_data(trans_id): |
| 2196 | + """ |
| 2197 | + This method is used to download binary data. |
| 2198 | + """ |
| 2199 | + |
| 2200 | + (status, error_msg, conn, trans_obj, |
| 2201 | + session_obj) = check_transaction_status(trans_id) |
| 2202 | + |
| 2203 | + cur = conn._Connection__async_cursor |
| 2204 | + register_binary_data_typecasters(cur) |
| 2205 | + if not status or conn is None or trans_obj is None or \ |
| 2206 | + session_obj is None: |
| 2207 | + return internal_server_error( |
| 2208 | + errormsg=TRANSACTION_STATUS_CHECK_FAILED |
| 2209 | + ) |
| 2210 | + |
| 2211 | + data = request.values if request.values else request.get_json(silent=True) |
| 2212 | + if data is None: |
| 2213 | + return make_json_response( |
| 2214 | + status=410, |
| 2215 | + success=0, |
| 2216 | + errormsg=gettext( |
| 2217 | + "Could not find the required parameter (query)." |
| 2218 | + ) |
| 2219 | + ) |
| 2220 | + col_pos = data['colpos'] |
| 2221 | + cur.scroll(int(data['rowpos'])) |
| 2222 | + binary_data = cur.fetchone() |
| 2223 | + binary_data = binary_data[col_pos] |
| 2224 | + |
| 2225 | + return send_file( |
| 2226 | + BytesIO(binary_data), |
| 2227 | + as_attachment=True, |
| 2228 | + download_name='binary_data', |
| 2229 | + mimetype='application/octet-stream' |
| 2230 | + ) |
| 2231 | + |
| 2232 | + |
2185 | 2233 | @blueprint.route( |
2186 | 2234 | '/status/<int:trans_id>', |
2187 | 2235 | methods=["GET"], |
|
0 commit comments