mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-01-24 15:26:46 -06:00
Ensure JSON data isn't modified in-flight by psycopg2 when using View/Edit data. Fixes #3600
This commit is contained in:
parent
a5d39003b6
commit
59446bb4b5
@ -25,6 +25,7 @@ Bug fixes
|
||||
| `Bug #3418 <https://redmine.postgresql.org/issues/3418>`_ - Allow editing of values in columns with the oid datatype which are not an actual row OID.
|
||||
| `Bug #3544 <https://redmine.postgresql.org/issues/3544>`_ - Make the Query Tool tab titles more concise and useful.
|
||||
| `Bug #3583 <https://redmine.postgresql.org/issues/3583>`_ - Update CodeMirror to 5.43.0 to resolve issues with auto-indent.
|
||||
| `Bug #3600 <https://redmine.postgresql.org/issues/3600>`_ - Ensure JSON data isn't modified in-flight by psycopg2 when using View/Edit data.
|
||||
| `Bug #3673 <https://redmine.postgresql.org/issues/3673>`_ - Modify the Download as CSV option to use the same connection as the Query Tool its running in so temporary tables etc. can be used.
|
||||
| `Bug #3873 <https://redmine.postgresql.org/issues/3873>`_ - Fix context sub-menu alignment on Safari.
|
||||
| `Bug #3906 <https://redmine.postgresql.org/issues/3906>`_ - Fix alignment of Close and Maximize button of Grant Wizard.
|
||||
|
@ -2,7 +2,7 @@
|
||||
{% set add_union = false %}
|
||||
{% if 'session_stats' in chart_names %}
|
||||
{% set add_union = true %}
|
||||
SELECT 'session_stats' AS chart_name, row_to_json(t) AS chart_data
|
||||
SELECT 'session_stats' AS chart_name, row_to_json(t)::jsonb AS chart_data
|
||||
FROM (SELECT
|
||||
(SELECT count(*) FROM pg_stat_activity{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Total') }}",
|
||||
(SELECT count(*) FROM pg_stat_activity WHERE state = 'active'{% if did %} AND datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Active') }}",
|
||||
@ -14,7 +14,7 @@ UNION ALL
|
||||
{% endif %}
|
||||
{% if 'tps_stats' in chart_names %}
|
||||
{% set add_union = true %}
|
||||
SELECT 'tps_stats' AS chart_name, row_to_json(t) AS chart_data
|
||||
SELECT 'tps_stats' AS chart_name, row_to_json(t)::jsonb AS chart_data
|
||||
FROM (SELECT
|
||||
(SELECT sum(xact_commit) + sum(xact_rollback) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Transactions') }}",
|
||||
(SELECT sum(xact_commit) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Commits') }}",
|
||||
@ -26,7 +26,7 @@ UNION ALL
|
||||
{% endif %}
|
||||
{% if 'ti_stats' in chart_names %}
|
||||
{% set add_union = true %}
|
||||
SELECT 'ti_stats' AS chart_name, row_to_json(t) AS chart_data
|
||||
SELECT 'ti_stats' AS chart_name, row_to_json(t)::jsonb AS chart_data
|
||||
FROM (SELECT
|
||||
(SELECT sum(tup_inserted) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Inserts') }}",
|
||||
(SELECT sum(tup_updated) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Updates') }}",
|
||||
@ -38,7 +38,7 @@ UNION ALL
|
||||
{% endif %}
|
||||
{% if 'to_stats' in chart_names %}
|
||||
{% set add_union = true %}
|
||||
SELECT 'to_stats' AS chart_name, row_to_json(t) AS chart_data
|
||||
SELECT 'to_stats' AS chart_name, row_to_json(t)::jsonb AS chart_data
|
||||
FROM (SELECT
|
||||
(SELECT sum(tup_fetched) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Fetched') }}",
|
||||
(SELECT sum(tup_returned) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Returned') }}"
|
||||
@ -49,7 +49,7 @@ UNION ALL
|
||||
{% endif %}
|
||||
{% if 'bio_stats' in chart_names %}
|
||||
{% set add_union = true %}
|
||||
SELECT 'bio_stats' AS chart_name, row_to_json(t) AS chart_data
|
||||
SELECT 'bio_stats' AS chart_name, row_to_json(t)::jsonb AS chart_data
|
||||
FROM (SELECT
|
||||
(SELECT sum(blks_read) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Reads') }}",
|
||||
(SELECT sum(blks_hit) FROM pg_stat_database{% if did %} WHERE datname = (SELECT datname FROM pg_database WHERE oid = {{ did }}){% endif %}) AS "{{ _('Hits') }}"
|
||||
|
@ -33,12 +33,12 @@
|
||||
|
||||
// return wrapper element
|
||||
function getWrapper() {
|
||||
return $('<div class=\'pg_text_editor\' />');
|
||||
return $('<div class=\'pg-text-editor\' />');
|
||||
}
|
||||
|
||||
// return textarea element
|
||||
function getTextArea() {
|
||||
return $('<textarea class=\'pg_textarea text-12\' hidefocus rows=5\'>');
|
||||
return $('<textarea class=\'pg-textarea text-12\' hidefocus rows=5\'>');
|
||||
}
|
||||
|
||||
// Generate and return editor buttons
|
||||
@ -107,7 +107,11 @@
|
||||
grid.copied_rows[row][cell] = 1;
|
||||
}
|
||||
} else {
|
||||
item[args.column.field] = state;
|
||||
if(column_type === 'jsonb') {
|
||||
item[args.column.field] = JSON.parse(state);
|
||||
} else {
|
||||
item[args.column.field] = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,6 +368,7 @@
|
||||
|
||||
this.loadValue = function(item) {
|
||||
var data = defaultValue = item[args.column.field];
|
||||
/* If jsonb or array */
|
||||
if (data && typeof data === 'object' && !Array.isArray(data)) {
|
||||
data = JSON.stringify(data, null, 4);
|
||||
} else if (Array.isArray(data)) {
|
||||
@ -377,6 +382,7 @@
|
||||
});
|
||||
data = '[' + temp.join() + ']';
|
||||
}
|
||||
/* if json take as is */
|
||||
$input.val(data);
|
||||
$input.trigger('select');
|
||||
};
|
||||
@ -388,8 +394,12 @@
|
||||
return $input.val();
|
||||
};
|
||||
|
||||
this.applyValue = function(item, state) {
|
||||
setValue(args, item, state, 'text');
|
||||
this.applyValue = function(item, state){
|
||||
if(args.column.column_type_internal === 'jsonb') {
|
||||
setValue(args, item, state, 'jsonb');
|
||||
} else {
|
||||
setValue(args, item, state, 'text');
|
||||
}
|
||||
};
|
||||
|
||||
this.isValueChanged = function() {
|
||||
@ -401,13 +411,17 @@
|
||||
};
|
||||
|
||||
this.validate = function() {
|
||||
if (args.column.validator) {
|
||||
var validationResults = args.column.validator($input.val());
|
||||
if (!validationResults.valid) {
|
||||
return validationResults;
|
||||
if(args.column.column_type_internal === 'jsonb') {
|
||||
try {
|
||||
JSON.parse($input.val());
|
||||
} catch(e) {
|
||||
$input.addClass('pg-text-invalid');
|
||||
return {
|
||||
valid: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
$input.removeClass('pg-text-invalid');
|
||||
return {
|
||||
valid: true,
|
||||
msg: null,
|
||||
|
@ -266,12 +266,6 @@ input.editor-checkbox:focus {
|
||||
}
|
||||
|
||||
/* Style for text editor */
|
||||
.pg_textarea {
|
||||
width:250px;
|
||||
height:80px;
|
||||
border:0;
|
||||
outline:0;
|
||||
}
|
||||
.pg_buttons {
|
||||
text-align:right;
|
||||
}
|
||||
|
@ -233,17 +233,26 @@ li.CodeMirror-hint-active {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.pg_text_editor {
|
||||
.pg-text-editor {
|
||||
z-index:10000;
|
||||
position:absolute;
|
||||
background: $color-bg-theme;
|
||||
padding: 0.25rem;
|
||||
border: $panel-border;
|
||||
box-shadow: $dropdown-box-shadow;
|
||||
}
|
||||
|
||||
.pg_text_editor textarea {
|
||||
resize: both;
|
||||
|
||||
& .pg-textarea {
|
||||
width:250px;
|
||||
height:80px;
|
||||
border:0;
|
||||
outline:0;
|
||||
resize: both;
|
||||
}
|
||||
|
||||
& .pg-text-invalid {
|
||||
background: $color-danger-lighter;
|
||||
}
|
||||
}
|
||||
|
||||
.sql-editor-message {
|
||||
|
@ -18,7 +18,6 @@ from flask import session
|
||||
from flask_babelex import gettext
|
||||
import psycopg2
|
||||
from psycopg2.extensions import adapt
|
||||
from psycopg2.extras import Json as psycopg2_json
|
||||
|
||||
import config
|
||||
from pgadmin.model import Server, User
|
||||
@ -226,14 +225,7 @@ class Driver(BaseDriver):
|
||||
|
||||
@staticmethod
|
||||
def qtLiteral(value):
|
||||
adapted = None
|
||||
|
||||
# adapt function cannot adapt dict data type
|
||||
# Used http://initd.org/psycopg/docs/extras.html#json-adaptation
|
||||
if type(value) == dict:
|
||||
adapted = psycopg2_json(value)
|
||||
else:
|
||||
adapted = adapt(value)
|
||||
adapted = adapt(value)
|
||||
|
||||
# Not all adapted objects have encoding
|
||||
# e.g.
|
||||
|
@ -17,6 +17,7 @@ import sys
|
||||
from psycopg2 import STRING as _STRING
|
||||
import psycopg2
|
||||
from psycopg2.extensions import encodings
|
||||
from psycopg2.extras import Json as psycopg2_json
|
||||
|
||||
from .encoding import configureDriverEncodings
|
||||
|
||||
@ -166,6 +167,14 @@ def register_global_typecasters():
|
||||
# array of string type
|
||||
psycopg2.extensions.register_type(pg_array_types_to_array_of_string_type)
|
||||
|
||||
# Treat JSON data as text because converting it to dict alters the data
|
||||
# which should not happen as per postgres docs
|
||||
psycopg2.extras.register_default_json(loads=lambda x: x)
|
||||
|
||||
# pysycopg2 adapt does not support dict by default. Need to register
|
||||
# Used http://initd.org/psycopg/docs/extras.html#json-adaptation
|
||||
psycopg2.extensions.register_adapter(dict, psycopg2_json)
|
||||
|
||||
|
||||
def register_string_typecasters(connection):
|
||||
# raw_unicode_escape used for SQL ASCII will escape the
|
||||
|
Loading…
Reference in New Issue
Block a user