Fix handling of array types as inputs to the debugger. Fixes #3354

This commit is contained in:
Akshay Joshi 2018-11-27 11:18:47 +00:00 committed by Dave Page
parent c79ac2f8d2
commit bdf9f3404f
6 changed files with 256 additions and 59 deletions

View File

@ -9,6 +9,7 @@ for it.
.. toctree::
release_notes_3_7
release_notes_3_6
release_notes_3_5
release_notes_3_4

View File

@ -0,0 +1,17 @@
***********
Version 3.7
***********
Release date: 2019-01-10
This release contains a number of features and fixes reported since the release of pgAdmin4 3.6
Features
********
Bug fixes
*********
| `Bug #3354 <https://redmine.postgresql.org/issues/3354>`_ - Fix handling of array types as inputs to the debugger.

View File

@ -799,7 +799,7 @@ define([
var arrayCellModel = Backbone.Model.extend({
defaults: {
value: undefined,
value: null,
},
});
@ -817,11 +817,41 @@ define([
render: function() {
var self = this,
arrayValuesCol = this.model.get(this.column.get('name')),
gridCols = [{
cell_type = 'string';
var data_type = this.model.get('type').replace('[]' ,'');
switch (data_type) {
case 'boolean':
cell_type = 'boolean';
break;
case 'integer':
case 'smallint':
case 'bigint':
case 'serial':
case 'smallserial':
case 'bigserial':
case 'oid':
case 'cid':
case 'xid':
case 'tid':
cell_type = 'integer';
break;
case 'real':
case 'numeric':
case 'double precision':
case 'decimal':
cell_type = 'number';
break;
case 'date':
cell_type = 'date';
break;
}
var gridCols = [{
name: 'value',
label: gettext('Array Values'),
type: 'text',
cell: 'string',
cell: cell_type,
headerCell: Backgrid.Extension.CustomHeaderIconCell,
cellHeaderClasses: 'width_percent_100',
}],
@ -844,6 +874,22 @@ define([
collection: arrayValuesCol,
});
this.grid.listenTo(arrayValuesCol, 'backgrid:error',
(function(obj) {
return function(ev) {
obj.model.trigger('backgrid:error', obj.model, obj.column, new Backgrid.Command(ev));
};
})(this)
);
this.grid.listenTo(arrayValuesCol, 'backgrid:edited',
(function(obj) {
return function(ev) {
obj.model.trigger('backgrid:edited', obj.model, obj.column, new Backgrid.Command(ev));
};
})(this)
);
grid.render();
gridBody.append(grid.$el);
@ -893,8 +939,6 @@ define([
self.grid = null;
}
}, 10);
}
}, 10);
return;
@ -944,8 +988,8 @@ define([
var values = [];
rawData.each(function(m) {
var val = m.get('value');
if (_.isUndefined(val)) {
values.push('null');
if (_.isUndefined(val) || _.isNull(val)) {
values.push('NULL');
} else {
values.push(m.get('value'));
}
@ -963,6 +1007,40 @@ define([
},
});
/*
* This will help us transform the user input numeric array values in proper format to be
* displayed in the cell.
*/
var InputNumberArrayCellFormatter= Backgrid.Extension.InputNumberArrayCellFormatter =
function() {};
_.extend(InputNumberArrayCellFormatter.prototype, {
/**
* Takes a raw value from a model and returns an optionally formatted
* string for display.
*/
fromRaw: function(rawData) {
var values = [];
rawData.each(function(m) {
var val = m.get('value');
if (_.isUndefined(val) || _.isNull(val)) {
values.push('NULL');
} else {
values.push(m.get('value'));
}
});
return values.toString();
},
toRaw: function(formattedData) {
formattedData.each(function(m) {
m.set('value', parseFloat(m.get('value')), {
silent: true,
});
});
return formattedData;
},
});
/*
* InputStringArrayCell for rendering and taking input for string array type in debugger
*/
@ -982,7 +1060,6 @@ define([
}
this.model.set(this.column.get('name'), this.collection);
this.listenTo(this.collection, 'remove', this.render);
},
});
@ -990,13 +1067,70 @@ define([
/*
* InputIntegerArrayCell for rendering and taking input for integer array type in debugger
*/
Backgrid.Extension.InputIntegerArrayCell = Backgrid.Cell.extend({
Backgrid.Extension.InputIntegerArrayCell = Backgrid.IntegerCell.extend({
className: 'width_percent_25',
formatter: InputIntegerArrayCellFormatter,
editor: InputArrayCellEditor,
initialize: function() {
Backgrid.Cell.prototype.initialize.apply(this, arguments);
Backgrid.IntegerCell.prototype.initialize.apply(this, arguments);
// set value to empty array.
var m = arguments[0].model;
_.each(m.get('value'), function(arrVal) {
if (arrVal.value === 'NULL') {
arrVal.value = null;
}
});
if (_.isUndefined(this.collection)) {
this.collection = new(Backbone.Collection.extend({
model: arrayCellModel,
}))(m.get('value'));
}
this.model.set(this.column.get('name'), this.collection);
this.listenTo(this.collection, 'remove', this.render);
},
});
/*
* InputNumberArrayCell for rendering and taking input for numeric array type in debugger
*/
Backgrid.Extension.InputNumberArrayCell = Backgrid.NumberCell.extend({
className: 'width_percent_25',
formatter: InputNumberArrayCellFormatter,
editor: InputArrayCellEditor,
initialize: function() {
Backgrid.NumberCell.prototype.initialize.apply(this, arguments);
// set value to empty array.
var m = arguments[0].model;
_.each(m.get('value'), function(arrVal) {
if (arrVal.value === 'NULL') {
arrVal.value = null;
}
});
if (_.isUndefined(this.collection)) {
this.collection = new(Backbone.Collection.extend({
model: arrayCellModel,
}))(m.get('value'));
}
this.model.set(this.column.get('name'), this.collection);
this.listenTo(this.collection, 'remove', this.render);
},
});
/*
* InputBooleanArrayCell for rendering and taking input for boolean array type in debugger
*/
Backgrid.Extension.InputBooleanArrayCell = Backgrid.BooleanCell.extend({
className: 'width_percent_25',
editor: InputArrayCellEditor,
initialize: function() {
Backgrid.BooleanCell.prototype.initialize.apply(this, arguments);
// set value to empty array.
var m = arguments[0].model;
if (_.isUndefined(this.collection)) {
@ -1005,9 +1139,7 @@ define([
}))(m.get('value'));
}
this.model.set(this.column.get('name'), this.collection);
this.listenTo(this.collection, 'remove', this.render);
},
});
@ -1479,6 +1611,22 @@ define([
remove: Backgrid.Extension.DependentCell.prototype.remove,
});
Backgrid.BooleanCellFormatter = _.extend(Backgrid.CellFormatter.prototype, {
fromRaw: function (rawValue) {
if (_.isUndefined(rawValue) || _.isNull(rawValue)) {
return false;
} else if (rawValue === '1' || rawValue === 'True') {
return true;
} else if (rawValue === '0' || rawValue === 'False') {
return false;
}
return rawValue;
},
toRaw: function (formattedData) {
return formattedData;
},
});
return Backgrid;
});

View File

@ -1810,7 +1810,10 @@ def set_arguments_sqlite(sid, did, scid, func_id):
if data[i]['value'].__class__.__name__ in (
'list') and data[i]['value']:
for k in range(0, len(data[i]['value'])):
array_string += data[i]['value'][k]['value']
if data[i]['value'][k]['value'] is None:
array_string += 'NULL'
else:
array_string += str(data[i]['value'][k]['value'])
if k != (len(data[i]['value']) - 1):
array_string += ','
elif data[i]['value'].__class__.__name__ in (

View File

@ -17,42 +17,76 @@ define([
// if variable type is an array then we need to render the custom control to take the input from user.
if (variable_type.indexOf('[]') != -1) {
if (variable_type.indexOf('integer') != -1) {
var data_type = variable_type.replace('[]' ,'');
switch (data_type) {
case 'boolean':
return Backgrid.Extension.InputBooleanArrayCell;
case 'integer':
case 'smallint':
case 'bigint':
case 'serial':
case 'smallserial':
case 'bigserial':
case 'oid':
case 'cid':
case 'xid':
case 'tid':
return Backgrid.Extension.InputIntegerArrayCell;
case 'real':
case 'numeric':
case 'double precision':
case 'decimal':
return Backgrid.Extension.InputNumberArrayCell;
default:
return Backgrid.Extension.InputStringArrayCell;
}
return Backgrid.Extension.InputStringArrayCell;
}
switch (variable_type) {
case 'bool':
return Backgrid.BooleanCell;
case 'integer':
// As we are getting this value as text from sqlite database so we need to type cast it.
if (model.get('value') != undefined) {
model.set({
'value': parseInt(model.get('value')),
}, {
silent: true,
} else {
switch (variable_type) {
case 'boolean':
return Backgrid.BooleanCell.extend({
formatter: Backgrid.BooleanCellFormatter,
});
}
case 'integer':
case 'smallint':
case 'bigint':
case 'serial':
case 'smallserial':
case 'bigserial':
case 'oid':
case 'cid':
case 'xid':
case 'tid':
// As we are getting this value as text from sqlite database so we need to type cast it.
if (model.get('value') != undefined) {
model.set({
'value': parseInt(model.get('value')),
}, {
silent: true,
});
}
return Backgrid.IntegerCell;
case 'real':
// As we are getting this value as text from sqlite database so we need to type cast it.
if (model.get('value') != undefined) {
model.set({
'value': parseFloat(model.get('value')),
}, {
silent: true,
});
return Backgrid.IntegerCell;
case 'real':
case 'numeric':
case 'double precision':
case 'decimal':
// As we are getting this value as text from sqlite database so we need to type cast it.
if (model.get('value') != undefined) {
model.set({
'value': parseFloat(model.get('value')),
}, {
silent: true,
});
}
return Backgrid.NumberCell;
case 'string':
return Backgrid.StringCell;
case 'date':
return Backgrid.DateCell;
default:
return Backgrid.Cell;
}
return Backgrid.NumberCell;
case 'string':
return Backgrid.StringCell;
case 'date':
return Backgrid.DateCell;
default:
return Backgrid.Cell;
}
};
@ -378,13 +412,6 @@ define([
values = [];
if (argtype[index].indexOf('[]') != -1) {
vals = func_args_data[i]['value'].split(',');
if (argtype[index].indexOf('integer') != -1) {
_.each(vals, function(val) {
values.push({
'value': parseInt(val),
});
});
}
_.each(vals, function(val) {
values.push({
'value': val,
@ -485,13 +512,6 @@ define([
values = [];
if (argtype[index].indexOf('[]') != -1) {
vals = func_args_data[i]['value'].split(',');
if (argtype[index].indexOf('integer') != -1) {
_.each(vals, function(val) {
values.push({
'value': parseInt(val),
});
});
}
_.each(vals, function(val) {
values.push({
'value': val,
@ -918,6 +938,14 @@ define([
};
})(this)
);
this.grid.listenTo(this.debuggerInputArgsColl, 'backgrid:error',
(function(obj) {
return function() {
obj.__internal.buttons[0].element.disabled = true;
};
})(this)
);
},
};
});

View File

@ -11,7 +11,7 @@
{% if data %}
{% for dict_item in data %}
{% if 'type' in dict_item and 'value' in dict_item %}
{% if dict_item['value'] != 'NULL' %}
{% if dict_item['value'] != 'NULL' and '[]' not in dict_item['type'] %}
{{ dict_item['value']|qtLiteral }}::{{ dict_item['type'] }}{% if not loop.last %}, {% endif %}
{% elif dict_item['value'] == 'NULL' %}
{{ dict_item['value'] }}::{{ dict_item['type'] }}{% if not loop.last %}, {% endif %}