1. Added Expression to CREATE INDEX. #2595

2. Added support for ALTER INDEX column statistics. #6375
This commit is contained in:
Anil Sahoo 2023-08-01 12:37:47 +05:30 committed by GitHub
parent 4920d25479
commit 7d7b8a71c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 1312 additions and 281 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -8,7 +8,7 @@ Use the *Index* dialog to create an index on a specified table or materialized
view. view.
The *Index* dialog organizes the development of a index through the following The *Index* dialog organizes the development of a index through the following
dialog tabs: *General* and *Definition*. The *SQL* tab displays the SQL code dialog tabs: *General*, *Definition*, and *Columns*. The *SQL* tab displays the SQL code
generated by dialog selections. generated by dialog selections.
.. image:: images/index_general.png .. image:: images/index_general.png
@ -76,28 +76,36 @@ Use the fields in the *Definition* tab to define the index:
expression limits the entries in the index to those rows that satisfy the expression limits the entries in the index to those rows that satisfy the
constraint. constraint.
Use the context-sensitive fields in the *Columns* panel to specify which Click the *Columns* tab to continue.
column(s) the index queries. Click the *Add* icon (+) to add a column:
* Use the drop-down listbox in *Column* field to select the name of the column .. image:: images/index_columns.png
rom the table. :alt: Index dialog columns tab
:align: center
Use the fields in the *Columns* tab to specify which column(s) or expression(s)
the index queries. Use the *Is expression ?* switch to enable
expression sql input. Use the drop-down listbox next to *Column*
to select a column. Once the *Column* is selected or the *Expression* is
entered then click the *Add* icon (+) to provide details of the action on the
column/expression:
* The *Col/Exp* field is populated with the selection made in the *Column*
drop-down listbox or the *Expression* entered.
* If enabled, use the drop-down listbox to select an available *Operator class* * If enabled, use the drop-down listbox to select an available *Operator class*
to specify the type of action performed on the column. to specify the type of action performed on the column.
* If enabled, move the *Sort order* switch to specify the sort order: * If enabled, use the drop-down listbox to select *Sort order*:
* Select *ASC* to specify an ascending sort order (the default); * Select *ASC* to specify an ascending sort order (the default);
* Select *DESC* to specify a descending sort order. * Select *DESC* to specify a descending sort order.
* If enabled, use the drop-down listbox to select *Nulls*:
* If enabled, move the *Nulls* switch to specify the sort order of nulls:
* Select *First* to specify nulls sort before non-nulls; * Select *First* to specify nulls sort before non-nulls;
* Select *Last* to specify nulls sort after non-nulls (the default). * Select *Last* to specify nulls sort after non-nulls (the default).
* Use the drop-down listbox in the *Collation* field to select a collation to * Use the drop-down listbox in the *Collation* field to select a collation to
use for the index. use for the index.
Use *Include columns* field to specify columns for *INCLUDE* clause of the Use *Include columns* field to specify columns for *INCLUDE* clause of the
index. This option is available in Postgres 11 and later. constraint. This option is available in Postgres 11 and later.
Click the *SQL* tab to continue. Click the *SQL* tab to continue.

View File

@ -7,7 +7,7 @@
// //
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
import IndexSchema, { getColumnSchema } from './index.ui'; import IndexSchema from './index.ui';
import { getNodeAjaxOptions, getNodeListByName } from 'pgbrowser/node_ajax'; import { getNodeAjaxOptions, getNodeListByName } from 'pgbrowser/node_ajax';
import _ from 'lodash'; import _ from 'lodash';
@ -46,7 +46,7 @@ define('pgadmin.node.index', [
hasSQL: true, hasSQL: true,
hasDepends: true, hasDepends: true,
hasStatistics: true, hasStatistics: true,
width: pgBrowser.stdW.md + 'px', width: pgBrowser.stdW.lg + 'px',
statsPrettifyFields: [gettext('Size'), gettext('Index size')], statsPrettifyFields: [gettext('Size'), gettext('Index size')],
url_jump_after_node: 'schema', url_jump_after_node: 'schema',
Init: function() { Init: function() {
@ -124,13 +124,14 @@ define('pgadmin.node.index', [
getSchema: (treeNodeInfo, itemNodeData) => { getSchema: (treeNodeInfo, itemNodeData) => {
let nodeObj = pgAdmin.Browser.Nodes['index']; let nodeObj = pgAdmin.Browser.Nodes['index'];
return new IndexSchema( return new IndexSchema(
()=>getColumnSchema(nodeObj, treeNodeInfo, itemNodeData),
{ {
tablespaceList: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{ tablespaceList: ()=>getNodeListByName('tablespace', treeNodeInfo, itemNodeData, {}, (m)=>{
return (m.label != 'pg_global'); return (m.label != 'pg_global');
}), }),
amnameList : ()=>getNodeAjaxOptions('get_access_methods', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}), amnameList : ()=>getNodeAjaxOptions('get_access_methods', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
columnList: ()=>getNodeListByName('column', treeNodeInfo, itemNodeData, {}), columnList: ()=>getNodeListByName('column', treeNodeInfo, itemNodeData, {}),
collationList: ()=>getNodeAjaxOptions('get_collations', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
opClassList: ()=>getNodeAjaxOptions('get_op_class', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'})
}, },
{ {
node_info: treeNodeInfo node_info: treeNodeInfo

View File

@ -9,65 +9,79 @@
import gettext from 'sources/gettext'; import gettext from 'sources/gettext';
import BaseUISchema from 'sources/SchemaView/base_schema.ui'; import BaseUISchema from 'sources/SchemaView/base_schema.ui';
import { getNodeAjaxOptions, getNodeListByName } from '../../../../../../../../static/js/node_ajax'; import DataGridViewWithHeaderForm from '../../../../../../../../../static/js/helpers/DataGridViewWithHeaderForm';
import _ from 'lodash'; import _ from 'lodash';
import { isEmptyString } from 'sources/validators'; import { isEmptyString } from 'sources/validators';
import Notify from '../../../../../../../../../static/js/helpers/Notifier'; import Notify from '../../../../../../../../../static/js/helpers/Notifier';
export function getColumnSchema(nodeObj, treeNodeInfo, itemNodeData) {
return new ColumnSchema( function inSchema(node_info) {
{ return node_info && 'catalog' in node_info;
columnList: ()=>getNodeListByName('column', treeNodeInfo, itemNodeData, {}),
collationList: ()=>getNodeAjaxOptions('get_collations', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'}),
opClassList: ()=>getNodeAjaxOptions('get_op_class', nodeObj, treeNodeInfo, itemNodeData, {jumpAfterNode: 'schema'})
}, {
node_info: treeNodeInfo
}
);
} }
export class ColumnSchema extends BaseUISchema { class IndexColHeaderSchema extends BaseUISchema {
constructor(fieldOptions = {}, nodeData = [], initValues={}) { constructor(columns) {
super({ super({
name: null, is_exp: true,
oid: undefined,
description: '',
is_sys_obj: false,
colname: undefined, colname: undefined,
collspcname: undefined, expression: undefined,
});
this.columns = columns;
}
changeColumnOptions(columns) {
this.columns = columns;
}
addDisabled(state) {
return !(state.is_exp ? state.expression : state.colname);
}
/* Data to IndexColumnSchema will be added using the header form */
getNewData(data) {
return this.indexColumnSchema.getNewData({
is_exp: data.is_exp,
colname: data.is_exp ? data.expression : data.colname,
});
}
get baseFields() {
return [{
id: 'is_exp', label: gettext('Is expression'), type:'switch', editable: false,
},{
id: 'colname', label: gettext('Column'), type: 'select', editable: false,
options: this.columns, deps: ['is_exp'],
optionsReloadBasis: this.columns?.map ? _.join(this.columns.map((c)=>c.label), ',') : null,
optionsLoaded: (res)=>this.columnOptions=res,
disabled: (state)=>state.is_exp, node: 'column',
},{
id: 'expression', label: gettext('Expression'), editable: false, deps: ['is_exp'],
type: 'sql', disabled: (state)=>!state.is_exp,
}];
}
}
class IndexColumnSchema extends BaseUISchema {
constructor(nodeData = {}) {
super({
colname: undefined,
is_exp: false,
op_class: undefined, op_class: undefined,
sort_order: false, sort_order: false,
nulls: false, nulls: false,
is_sort_nulls_applicable: true, is_sort_nulls_applicable: false,
...initValues collspcname:undefined
}); });
this.fieldOptions = {
columnList: [],
collationList: [],
opClassList: [],
...fieldOptions
};
this.node_info = { this.node_info = {
...nodeData.node_info ...nodeData
}; };
this.operClassOptions = [];
this.collationOptions = [];
this.op_class_types = []; this.op_class_types = [];
} }
get idAttribute() {
return 'oid';
}
// We will check if we are under schema node & in 'create' mode
inSchemaWithModelCheck(state) {
if(this.node_info && 'schema' in this.node_info) {
// We will disable control if it's in 'edit' mode
return !this.isNew(state);
}
return true;
}
setOpClassTypes(options) { setOpClassTypes(options) {
if(!options || (_.isArray(options) && options.length == 0)) if(!options || (_.isArray(options) && options.length == 0))
return this.op_class_types; return this.op_class_types;
@ -88,37 +102,52 @@ export class ColumnSchema extends BaseUISchema {
return false; return false;
} }
setOperClassOptions(options) {
this.operClassOptions = options;
}
setCollationOptions(options) {
this.collationOptions = options;
}
getNewData(data) {
return {
...super.getNewData(data),
};
}
// We will check if we are under schema node & in 'create' mode
inSchemaWithModelCheck(state) {
if(this.node_info && 'schema' in this.node_info) {
// We will disable control if it's in 'edit' mode
return !this.isNew(state);
}
return true;
}
get baseFields() { get baseFields() {
let columnSchemaObj = this; let obj = this;
return [ return [
{ {
id: 'colname', label: gettext('Column'), id: 'is_exp', label: '', type:'', cell: '', editable: false, width: 20,
type: 'select', cell: 'select', noEmpty: true, disableResizing: true,
disabled: () => inSchema(columnSchemaObj.node_info), controlProps: {
editable: function (state) { formatter: {
return !columnSchemaObj.inSchemaWithModelCheck(state); fromRaw: function (rawValue) {
}, return rawValue ? 'E' : 'C';
options: columnSchemaObj.fieldOptions.columnList, },
node: 'column', }
}, visible: false,
},{ },{
id: 'collspcname', label: gettext('Collation'), id: 'colname', label: gettext('Col/Exp'), type:'', editable: false,
type: 'select', cell:'', width: 100,
cell: 'select',
disabled: () => inSchema(columnSchemaObj.node_info),
editable: function (state) {
return !columnSchemaObj.inSchemaWithModelCheck(state);
},
options: columnSchemaObj.fieldOptions.collationList,
node: 'index',
url_jump_after_node: 'schema',
},{ },{
id: 'op_class', label: gettext('Operator class'), id: 'op_class', label: gettext('Operator class'), tags: true, type: 'select',
tags: true, type: 'select',
cell: () => { cell: () => {
return { return {
cell: 'select', cell: 'select',
options: columnSchemaObj.fieldOptions.opClassList, options: obj.operClassOptions,
optionsLoaded: (options)=>{columnSchemaObj.setOpClassTypes(options);}, optionsLoaded: (options)=>{obj.setOpClassTypes(options);},
controlProps: { controlProps: {
allowClear: true, allowClear: true,
filter: (options) => { filter: (options) => {
@ -126,12 +155,12 @@ export class ColumnSchema extends BaseUISchema {
* to access method selected by user if not selected * to access method selected by user if not selected
* send btree related op_class options * send btree related op_class options
*/ */
let amname = columnSchemaObj._top?._sessData ? columnSchemaObj._top?._sessData.amname : columnSchemaObj._top?._origData.amname; let amname = obj._top?._sessData ? obj._top?._sessData.amname : obj._top?._origData.amname;
if(_.isUndefined(amname)) if(_.isUndefined(amname))
return options; return options;
_.each(this.op_class_types, function(v, k) { _.each(obj.op_class_types, function(v, k) {
if(amname === k) { if(amname === k) {
options = v; options = v;
} }
@ -142,14 +171,13 @@ export class ColumnSchema extends BaseUISchema {
}; };
}, },
editable: function (state) { editable: function (state) {
return !columnSchemaObj.inSchemaWithModelCheck(state); return !obj.inSchemaWithModelCheck(state);
}, },
node: 'index', node: 'index',
url_jump_after_node: 'schema', url_jump_after_node: 'schema',
deps: ['amname'], deps: ['amname'],
},{ },{
id: 'sort_order', label: gettext('Sort order'), id: 'sort_order', label: gettext('Sort order'), type: 'select', cell: 'select',
type: 'select', cell: 'select',
options: [ options: [
{label: 'ASC', value: false}, {label: 'ASC', value: false},
{label: 'DESC', value: true}, {label: 'DESC', value: true},
@ -174,22 +202,38 @@ export class ColumnSchema extends BaseUISchema {
} }
}, },
editable: function(state) { editable: function(state) {
return columnSchemaObj.isEditable(state); return obj.isEditable(state);
}, },
deps: ['amname'], deps: ['amname'],
},{ },{
id: 'nulls', label: gettext('NULLs'), id: 'nulls', label: gettext('NULLs'), type:'select', cell: 'select',
editable: function(state) {
return columnSchemaObj.isEditable(state);
},
deps: ['amname', 'sort_order'],
type:'select', cell: 'select',
options: [ options: [
{label: 'FIRST', value: true}, {label: 'FIRST', value: true},
{label: 'LAST', value: false}, {label: 'LAST', value: false},
], controlProps: {allowClear: false}, ], controlProps: {allowClear: false},
width: 110, disableResizing: true, width: 110, disableResizing: true,
}, editable: function(state) {
return obj.isEditable(state);
},
deps: ['amname', 'sort_order'],
},{
id: 'collspcname', label: gettext('Collation'),
type: 'select',
cell: 'select',
disabled: () => inSchema(obj.node_info),
editable: function (state) {
return !obj.inSchemaWithModelCheck(state);
},
options: obj.collationOptions,
node: 'index',
url_jump_after_node: 'schema',
},{
id: 'statistics', label: gettext('Statistics'),
type: 'int', cell: 'int', disabled: (state)=> {
return (!state.is_exp || obj.node_info.server.version < 110000);
},
min: -1, max: 10000, mode: ['edit','properties'],
}
]; ];
} }
} }
@ -298,12 +342,8 @@ export class WithSchema extends BaseUISchema {
} }
} }
function inSchema(node_info) {
return node_info && 'catalog' in node_info;
}
export default class IndexSchema extends BaseUISchema { export default class IndexSchema extends BaseUISchema {
constructor(columnSchema, fieldOptions = {}, nodeData = [], initValues={}) { constructor(fieldOptions = {}, nodeData = {}, initValues={}) {
super({ super({
name: undefined, name: undefined,
oid: undefined, oid: undefined,
@ -322,12 +362,16 @@ export default class IndexSchema extends BaseUISchema {
tablespaceList: [], tablespaceList: [],
amnameList: [], amnameList: [],
columnList: [], columnList: [],
opClassList: [],
collationList: [],
...fieldOptions ...fieldOptions
}; };
this.node_info = { this.node_info = {
...nodeData.node_info ...nodeData.node_info
}; };
this.getColumnSchema = columnSchema; this.indexHeaderSchema = new IndexColHeaderSchema(this.fieldOptions.columnList);
this.indexColumnSchema = new IndexColumnSchema(this.node_info);
this.indexHeaderSchema.indexColumnSchema = this.indexColumnSchema;
this.withSchema = new WithSchema(this.node_info); this.withSchema = new WithSchema(this.node_info);
} }
@ -335,6 +379,16 @@ export default class IndexSchema extends BaseUISchema {
return 'oid'; return 'oid';
} }
initialise() {
this.indexColumnSchema.setOperClassOptions(this.fieldOptions.opClassList);
this.indexColumnSchema.setCollationOptions(this.fieldOptions.collationList);
}
changeColumnOptions(columns) {
this.indexHeaderSchema.changeColumnOptions(columns);
this.fieldOptions.columns = columns;
}
getColumns() { getColumns() {
return { return {
type: 'select', type: 'select',
@ -412,16 +466,15 @@ export default class IndexSchema extends BaseUISchema {
}; };
}, },
deferredDepChange: (state, source, topState, actionObj) => { deferredDepChange: (state, source, topState, actionObj) => {
const setColumns = (resolve)=>{ const setColumns = (resolve)=>{
resolve(()=>{ resolve(()=>{
state.columns.splice(0, state.columns.length); state.columns.splice(0, state.columns?.length);
return { return {
columns: state.columns, columns: state.columns,
}; };
}); });
}; };
if((state.amname != actionObj.oldState.amname) && state.columns.length > 0) { if((state.amname != actionObj?.oldState.amname) && state.columns?.length > 0) {
return new Promise((resolve)=>{ return new Promise((resolve)=>{
Notify.confirm( Notify.confirm(
gettext('Warning'), gettext('Warning'),
@ -431,7 +484,7 @@ export default class IndexSchema extends BaseUISchema {
}, },
function() { function() {
resolve(()=>{ resolve(()=>{
state.amname = actionObj.oldState.amname; state.amname = actionObj?.oldState.amname;
return { return {
amname: state.amname, amname: state.amname,
}; };
@ -443,22 +496,6 @@ export default class IndexSchema extends BaseUISchema {
return Promise.resolve(()=>{/*This is intentional (SonarQube)*/}); return Promise.resolve(()=>{/*This is intentional (SonarQube)*/});
} }
}, },
},
{
id: 'include', label: gettext('Include columns'),
group: gettext('Definition'),
editable: false, canDelete: true, canAdd: true, mode: ['properties'],
disabled: () => inSchema(indexSchemaObj.node_info),
readonly: function (state) {
return !indexSchemaObj.isNew(state);
},
type: () => {
return indexSchemaObj.getColumns();
},
visible: function() {
return indexSchemaObj.isVisible();
},
node:'column',
},{ },{
type: 'nested-fieldset', label: gettext('With'), group: gettext('Definition'), type: 'nested-fieldset', label: gettext('With'), group: gettext('Definition'),
schema: this.withSchema, schema: this.withSchema,
@ -529,29 +566,36 @@ export default class IndexSchema extends BaseUISchema {
}, },
mode: ['create', 'edit'], mode: ['create', 'edit'],
control: 'sql-field', visible: true, group: gettext('Definition'), control: 'sql-field', visible: true, group: gettext('Definition'),
}, { },{
id: 'columns', label: gettext('Columns'), type: 'collection', deps: ['amname'], id: 'columns', label: gettext('Columns/Expressions'),
group: gettext('Definition'), schema: indexSchemaObj.getColumnSchema(), group: gettext('Columns'), type: 'collection',
mode: ['edit', 'create', 'properties'], mode: ['create', 'edit', 'properties'],
canAdd: function(state) { editable: false, schema: this.indexColumnSchema,
// We will disable it if it's in 'edit' mode headerSchema: this.indexHeaderSchema, headerVisible: (state)=>indexSchemaObj.isNew(state),
CustomControl: DataGridViewWithHeaderForm,
uniqueCol: ['colname'],
canAdd: false, canDelete: function(state) {
// We can't update columns of existing
return indexSchemaObj.isNew(state); return indexSchemaObj.isNew(state);
}, }, cell: ()=>({
canEdit: false, cell: '',
canDelete: function(state) { controlProps: {
// We will disable it if it's in 'edit' mode formatter: {
return indexSchemaObj.isNew(state); fromRaw: (rawValue)=>{
}, return _.map(rawValue || [], 'colname').join(', ');
uniqueCol : ['colname'], },
columns: ['colname', 'op_class', 'sort_order', 'nulls', 'collspcname'] }
}, { },
width: 245,
})
},{
id: 'include', label: gettext('Include columns'), id: 'include', label: gettext('Include columns'),
type: () => { type: () => {
return indexSchemaObj.getColumns(); return indexSchemaObj.getColumns();
}, },
group: gettext('Definition'), group: gettext('Columns'),
editable: false, editable: false,
canDelete: true, canAdd: true, mode: ['edit', 'create'], canDelete: true, canAdd: true, mode: ['edit', 'create', 'properties'],
disabled: () => inSchema(indexSchemaObj.node_info), disabled: () => inSchema(indexSchemaObj.node_info),
readonly: function (state) { readonly: function (state) {
return !indexSchemaObj.isNew(state); return !indexSchemaObj.isNew(state);
@ -590,7 +634,7 @@ export default class IndexSchema extends BaseUISchema {
// Checks if columns is empty // Checks if columns is empty
let cols = state.columns; let cols = state.columns;
if(_.isArray(cols) && cols.length == 0){ if(_.isArray(cols) && cols.length == 0){
msg = gettext('You must specify at least one column.'); msg = gettext('You must specify at least one column/expression.');
setError('columns', msg); setError('columns', msg);
return true; return true;
} }

View File

@ -0,0 +1,14 @@
-- Index: Idx3_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx3_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx3_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, lower(name) COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx3_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,16 @@
-- Index: Idx1_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx1_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.test_table_for_indexes
CLUSTER ON "Idx1_$%{}[]()&*^!@""'`\/#";
COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,12 @@
-- Index: Idx1_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx1_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
TABLESPACE pg_default;
COMMENT ON INDEX public."Idx1_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,14 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,10 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,14 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,10 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,9 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
TABLESPACE pg_default;

View File

@ -0,0 +1,5 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
TABLESPACE pg_default;

View File

@ -0,0 +1,14 @@
-- Index: Idx_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,10 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,14 @@
-- Index: Idx3_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx3_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx3_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, lower(name) COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx3_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,10 @@
CREATE UNIQUE INDEX "Idx3_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, (lower(name)) COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx3_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,364 @@
{
"scenarios": [
{
"type": "create",
"name": "Create Table for indexes",
"endpoint": "NODE-table.obj",
"sql_endpoint": "NODE-table.sql_id",
"data": {
"name": "test_table_for_indexes",
"columns": [{
"name": "id",
"cltype": "bigint",
"is_primary_key": true
}, {
"name": "name",
"cltype": "text"
}],
"is_partitioned": false,
"spcname": "pg_default",
"schema": "public"
},
"store_object_id": true
},
{
"type": "create",
"name": "Create btree index with ASC and NULLS LAST -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"colname":"name",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_asc_null_last.sql",
"expected_msql_file": "create_btree_asc_null_last_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 11 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "create",
"name": "Create btree index with ASC and NULLS FIRST -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":true,
"is_sort_nulls_applicable":true
}, {
"colname":"name",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":true,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_asc_null_first.sql",
"expected_msql_file": "create_btree_asc_null_first_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 11 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "create",
"name": "Create btree index with DESC and NULLS LAST -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":true,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"colname":"name",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":true,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_desc_null_last.sql",
"expected_msql_file": "create_btree_desc_null_last_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 11 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "create",
"name": "Create btree index with DESC and NULLS FIRST -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":true,
"nulls":true,
"is_sort_nulls_applicable":true
}, {
"colname":"name",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":true,
"nulls":true,
"is_sort_nulls_applicable":true
}],
"indisunique":true,
"indisclustered":false,
"isconcurrent":false
},
"expected_sql_file": "create_btree_desc_null_first.sql",
"expected_msql_file": "create_btree_desc_null_first_msql.sql"
},
{
"type": "alter",
"name": "Alter index name, fill factor, comment and clustered -- 11 Plus",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx1_$%{}[]()&*^!@\"'`\\/#",
"description":"Test Comment",
"fillfactor":"10",
"indisclustered":true
},
"expected_sql_file": "alter_name_fillfactor_comment.sql",
"expected_msql_file": "alter_name_fillfactor_comment_msql.sql"
},
{
"type": "alter",
"name": "Alter reset fill factor and cluster -- 11 Plus",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"fillfactor": "",
"indisclustered": false
},
"expected_sql_file": "alter_reset_fillfactor_cluster.sql",
"expected_msql_file": "alter_reset_fillfactor_cluster_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 11 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx1_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "create",
"name": "Create btree index with expression and ASC and NULLS LAST -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx3_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"is_exp": true,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_expr_asc_null_last.sql",
"expected_msql_file": "create_btree_expr_asc_null_last_msql.sql"
},
{
"type": "alter",
"name": "Alter index statistics of expression -- 11 Plus",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#",
"columns":{
"changed": [{
"is_exp": true,
"col_num": 2,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true,
"statistics": 1000
}]
}
},
"expected_sql_file": "alter_expr_statistics.sql",
"expected_msql_file": "alter_expr_statistics_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 11 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "create",
"name": "Create hash index -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname": "pg_default",
"amname": "hash",
"columns": [{
"colname": "id",
"collspcname": "",
"op_class": "",
"sort_order": false,
"nulls": false,
"is_sort_nulls_applicable": false
}],
"indisunique": false,
"indisclustered": false,
"isconcurrent": false
},
"expected_sql_file": "create_hash_index.sql",
"expected_msql_file": "create_hash_index_msql.sql"
},
{
"type": "delete",
"name": "Drop hash index -- 11 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#"
}
},
{
"type": "delete",
"name": "Drop Table",
"endpoint": "NODE-table.delete_id",
"data": {
"name": "test_table_for_indexes"
}
},
{
"type": "create",
"name": "Create unnamed hash index -- 11 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"spcname": "pg_default",
"amname": "hash",
"columns": [{
"colname": "id",
"collspcname": "",
"op_class": "",
"sort_order": false,
"nulls": false,
"is_sort_nulls_applicable": false
}],
"indisunique": false,
"isconcurrent": false
},
"expected_msql_file": "create_unnamed_hash_index_msql.sql"
},
{
"type": "delete",
"name": "Drop hash index -- 11 Plus",
"endpoint": "NODE-index.delete_id"
}
]
}

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST) (id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False) WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default TABLESPACE pg_default
WHERE id < 100; WHERE id < 100;

View File

@ -1,6 +1,7 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST) (id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False) WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default TABLESPACE pg_default
WHERE id < 100; WHERE id < 100;

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST) (id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False) WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default TABLESPACE pg_default
WHERE id < 100; WHERE id < 100;

View File

@ -1,6 +1,7 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST) (id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False) WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default TABLESPACE pg_default
WHERE id < 100; WHERE id < 100;

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST) (id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False) WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default TABLESPACE pg_default
WHERE id < 100; WHERE id < 100;

View File

@ -1,6 +1,7 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST) (id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST)
INCLUDE(name, id)
WITH (fillfactor=10, deduplicate_items=False) WITH (fillfactor=10, deduplicate_items=False)
TABLESPACE pg_default TABLESPACE pg_default
WHERE id < 100; WHERE id < 100;

View File

@ -23,7 +23,7 @@
}, },
{ {
"type": "create", "type": "create",
"name": "Create btree index with ASC and NULLS LAST -- 15 Plus", "name": "Create btree index with ASC and NULLS LAST -- 13 Plus",
"endpoint": "NODE-index.obj", "endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql", "msql_endpoint": "NODE-index.msql",
@ -31,6 +31,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -60,7 +61,7 @@
}, },
{ {
"type": "delete", "type": "delete",
"name": "Drop index", "name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id", "endpoint": "NODE-index.delete_id",
"data": { "data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#" "name": "Idx_$%{}[]()&*^!@\"'`\\/#"
@ -76,6 +77,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -105,7 +107,7 @@
}, },
{ {
"type": "delete", "type": "delete",
"name": "Drop index -- 15 Plus", "name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id", "endpoint": "NODE-index.delete_id",
"data": { "data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#" "name": "Idx_$%{}[]()&*^!@\"'`\\/#"
@ -113,7 +115,7 @@
}, },
{ {
"type": "create", "type": "create",
"name": "Create btree index with DESC and NULLS LAST -- 15 Plus", "name": "Create btree index with DESC and NULLS LAST -- 13 Plus",
"endpoint": "NODE-index.obj", "endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql", "msql_endpoint": "NODE-index.msql",
@ -121,6 +123,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -150,7 +153,7 @@
}, },
{ {
"type": "delete", "type": "delete",
"name": "Drop index -- 15 Plus", "name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id", "endpoint": "NODE-index.delete_id",
"data": { "data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#" "name": "Idx_$%{}[]()&*^!@\"'`\\/#"
@ -158,7 +161,7 @@
}, },
{ {
"type": "create", "type": "create",
"name": "Create btree index with DESC and NULLS FIRST -- 15 Plus", "name": "Create btree index with DESC and NULLS FIRST -- 13 Plus",
"endpoint": "NODE-index.obj", "endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql", "msql_endpoint": "NODE-index.msql",
@ -166,6 +169,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -191,7 +195,7 @@
}, },
{ {
"type": "alter", "type": "alter",
"name": "Alter index name, fill factor, comment and clustered -- 15 Plus", "name": "Alter index name, fill factor, comment and clustered -- 13 Plus",
"endpoint": "NODE-index.obj_id", "endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id", "msql_endpoint": "NODE-index.msql_id",
@ -206,7 +210,7 @@
}, },
{ {
"type": "alter", "type": "alter",
"name": "Alter reset fill factor and cluster -- 15 Plus", "name": "Alter reset fill factor and cluster -- 13 Plus",
"endpoint": "NODE-index.obj_id", "endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id", "msql_endpoint": "NODE-index.msql_id",
@ -219,15 +223,85 @@
}, },
{ {
"type": "delete", "type": "delete",
"name": "Drop index -- 15 Plus", "name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id", "endpoint": "NODE-index.delete_id",
"data": { "data": {
"name": "Idx1_$%{}[]()&*^!@\"'`\\/#" "name": "Idx1_$%{}[]()&*^!@\"'`\\/#"
} }
}, },
{
"type": "create",
"name": "Create btree index with expression and ASC and NULLS LAST -- 13 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx3_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"is_exp": true,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_expr_asc_null_last.sql",
"expected_msql_file": "create_btree_expr_asc_null_last_msql.sql"
},
{
"type": "alter",
"name": "Alter index statistics of expression -- 13 Plus",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#",
"columns":{
"changed": [{
"is_exp": true,
"col_num": 2,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true,
"statistics": 1000
}]
}
},
"expected_sql_file": "alter_expr_statistics.sql",
"expected_msql_file": "alter_expr_statistics_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 13 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#"
}
},
{ {
"type": "create", "type": "create",
"name": "Create hash index -- 15 Plus", "name": "Create hash index -- 13 Plus",
"endpoint": "NODE-index.obj", "endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql", "msql_endpoint": "NODE-index.msql",
@ -252,7 +326,7 @@
}, },
{ {
"type": "delete", "type": "delete",
"name": "Drop hash index -- 15 Plus", "name": "Drop hash index -- 13 Plus",
"endpoint": "NODE-index.delete_id", "endpoint": "NODE-index.delete_id",
"data": { "data": {
"name": "Idx_$%{}[]()&*^!@\"'`\\/#" "name": "Idx_$%{}[]()&*^!@\"'`\\/#"
@ -268,7 +342,7 @@
}, },
{ {
"type": "create", "type": "create",
"name": "Create unnamed hash index -- 15 Plus", "name": "Create unnamed hash index -- 13 Plus",
"endpoint": "NODE-index.obj", "endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id", "sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql", "msql_endpoint": "NODE-index.msql",
@ -290,9 +364,8 @@
}, },
{ {
"type": "delete", "type": "delete",
"name": "Drop hash index -- 15 Plus", "name": "Drop hash index -- 13 Plus",
"endpoint": "NODE-index.delete_id" "endpoint": "NODE-index.delete_id"
} }
] ]
} }

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST) (id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default; TABLESPACE pg_default;

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx1_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST) (id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
TABLESPACE pg_default; TABLESPACE pg_default;

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST) (id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default TABLESPACE pg_default

View File

@ -1,6 +1,7 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST) (id ASC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS FIRST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default TABLESPACE pg_default

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST) (id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default TABLESPACE pg_default

View File

@ -1,6 +1,7 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST) (id ASC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default TABLESPACE pg_default

View File

@ -5,5 +5,6 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST) (id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
TABLESPACE pg_default; TABLESPACE pg_default;

View File

@ -1,5 +1,6 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST) (id DESC NULLS FIRST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS FIRST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
TABLESPACE pg_default; TABLESPACE pg_default;

View File

@ -5,6 +5,7 @@
CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX IF NOT EXISTS "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST) (id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default TABLESPACE pg_default

View File

@ -1,6 +1,7 @@
CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#" CREATE UNIQUE INDEX "Idx_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree ON public.test_table_for_indexes USING btree
(id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST) (id DESC NULLS LAST, name COLLATE pg_catalog."POSIX" text_pattern_ops DESC NULLS LAST)
INCLUDE(name, id)
NULLS NOT DISTINCT NULLS NOT DISTINCT
WITH (fillfactor=10) WITH (fillfactor=10)
TABLESPACE pg_default TABLESPACE pg_default

View File

@ -31,6 +31,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -75,6 +76,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -119,6 +121,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -163,6 +166,7 @@
"name":"Idx_$%{}[]()&*^!@\"'`\\/#", "name":"Idx_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default", "spcname":"pg_default",
"amname":"btree", "amname":"btree",
"include": ["name", "id"],
"columns":[{ "columns":[{
"colname":"id", "colname":"id",
"collspcname":"", "collspcname":"",
@ -222,6 +226,76 @@
"name": "Idx1_$%{}[]()&*^!@\"'`\\/#" "name": "Idx1_$%{}[]()&*^!@\"'`\\/#"
} }
}, },
{
"type": "create",
"name": "Create btree index with expression and ASC and NULLS LAST -- 15 Plus",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx3_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"include": ["name", "id"],
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"is_exp": true,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_expr_asc_null_last.sql",
"expected_msql_file": "create_btree_expr_asc_null_last_msql.sql"
},
{
"type": "alter",
"name": "Alter index statistics of expression -- 15 Plus",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#",
"columns":{
"changed": [{
"is_exp": true,
"col_num": 2,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true,
"statistics": 1000
}]
}
},
"expected_sql_file": "alter_expr_statistics.sql",
"expected_msql_file": "alter_expr_statistics_msql.sql"
},
{
"type": "delete",
"name": "Drop index -- 15 Plus",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#"
}
},
{ {
"type": "create", "type": "create",
"name": "Create hash index -- 15 Plus", "name": "Create hash index -- 15 Plus",

View File

@ -0,0 +1,13 @@
-- Index: Idx3_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx3_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx3_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, lower(name) COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx3_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,2 @@
ALTER INDEX IF EXISTS public."Idx3_$%{}[]()&*^!@""'`\/#"
ALTER COLUMN 2 SET STATISTICS 1000;

View File

@ -0,0 +1,13 @@
-- Index: Idx3_$%{}[]()&*^!@"'`\/#
-- DROP INDEX IF EXISTS public."Idx3_$%{}[]()&*^!@""'`\/#";
CREATE UNIQUE INDEX IF NOT EXISTS "Idx3_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, lower(name) COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx3_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -0,0 +1,9 @@
CREATE UNIQUE INDEX "Idx3_$%{}[]()&*^!@""'`\/#"
ON public.test_table_for_indexes USING btree
(id ASC NULLS LAST, (lower(name)) COLLATE pg_catalog."POSIX" text_pattern_ops ASC NULLS LAST)
WITH (fillfactor=10)
TABLESPACE pg_default
WHERE id < 100;
COMMENT ON INDEX public."Idx3_$%{}[]()&*^!@""'`\/#"
IS 'Test Comment';

View File

@ -150,6 +150,75 @@
"name": "Idx_$%{}[]()&*^!@\"'`\\/#" "name": "Idx_$%{}[]()&*^!@\"'`\\/#"
} }
}, },
{
"type": "create",
"name": "Create btree index with expression and ASC and NULLS LAST",
"endpoint": "NODE-index.obj",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql",
"data": {
"name":"Idx3_$%{}[]()&*^!@\"'`\\/#",
"spcname":"pg_default",
"amname":"btree",
"columns":[{
"colname":"id",
"collspcname":"",
"op_class":"",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}, {
"is_exp": true,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true
}],
"description":"Test Comment",
"fillfactor":"10",
"indisunique":true,
"indisclustered":false,
"isconcurrent":false,
"indconstraint":"id < 100"
},
"expected_sql_file": "create_btree_expr_asc_null_last.sql",
"expected_msql_file": "create_btree_expr_asc_null_last_msql.sql"
},
{
"type": "alter",
"name": "Alter index statistics of expression",
"endpoint": "NODE-index.obj_id",
"sql_endpoint": "NODE-index.sql_id",
"msql_endpoint": "NODE-index.msql_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#",
"columns":{
"changed": [{
"is_exp": true,
"col_num": 2,
"colname":"lower(name)",
"collspcname":"pg_catalog.\"POSIX\"",
"op_class":"text_pattern_ops",
"sort_order":false,
"nulls":false,
"is_sort_nulls_applicable":true,
"statistics": 1000
}]
}
},
"expected_sql_file": "alter_expr_statistics.sql",
"expected_msql_file": "alter_expr_statistics_msql.sql"
},
{
"type": "delete",
"name": "Drop index",
"endpoint": "NODE-index.delete_id",
"data": {
"name": "Idx3_$%{}[]()&*^!@\"'`\\/#"
}
},
{ {
"type": "create", "type": "create",
"name": "Create btree index with DESC and NULLS FIRST", "name": "Create btree index with DESC and NULLS FIRST",

View File

@ -79,7 +79,7 @@
} }
}, },
{ {
"name": "Create index: With valid data mumtiple.", "name": "Create index: With valid data with multiple columns.",
"is_positive_test": true, "is_positive_test": true,
"inventory_data": {}, "inventory_data": {},
"test_data": { "test_data": {
@ -110,6 +110,39 @@
"test_result_data": {} "test_result_data": {}
} }
}, },
{
"name": "Create index: With valid data with multiple columns and expressions.",
"is_positive_test": true,
"inventory_data": {},
"test_data": {
"name": "test_index_add",
"spcname": "pg_default",
"amname": "btree",
"columns": [
{
"is_exp": true,
"colname": "lower(name)",
"sort_order": false,
"nulls": false
},
{
"colname": "id",
"sort_order": true,
"nulls": false
}
],
"include": [
"name"
]
},
"mocking_required": false,
"mock_data": {},
"expected_data": {
"status_code": 200,
"error_msg": null,
"test_result_data": {}
}
},
{ {
"name": "Create index: With invalid data - No column name.", "name": "Create index: With invalid data - No column name.",
"is_positive_test": false, "is_positive_test": false,
@ -507,6 +540,24 @@
}, },
"is_list": false "is_list": false
}, },
{
"name": "Put index statistics : With existing index id.",
"is_positive_test": true,
"update_statistics": true,
"inventory_data": {
},
"test_data": {
"columns": "PLACE_HOLDER"
},
"mocking_required": false,
"mock_data": {},
"expected_data": {
"status_code": 200,
"error_msg": null,
"test_result_data": {}
},
"is_list": false
},
{ {
"name": "Put index : With existing index id while server is down.", "name": "Put index : With existing index id while server is down.",
"is_positive_test": false, "is_positive_test": false,

View File

@ -57,6 +57,8 @@ class IndexesUpdateTestCase(BaseTestGenerator):
self.schema_name, self.schema_name,
self.table_name, self.table_name,
self.column_name) self.column_name)
if hasattr(self, "update_statistics"):
self.column_name = "lower(%s)" % self.column_name
self.index_name = "test_index_delete_%s" % (str(uuid.uuid4())[1:8]) self.index_name = "test_index_delete_%s" % (str(uuid.uuid4())[1:8])
self.index_id = indexes_utils.create_index(self.server, self.db_name, self.index_id = indexes_utils.create_index(self.server, self.db_name,
self.schema_name, self.schema_name,
@ -70,6 +72,15 @@ class IndexesUpdateTestCase(BaseTestGenerator):
self.index_name) self.index_name)
if not index_response: if not index_response:
raise Exception("Could not find the index to update.") raise Exception("Could not find the index to update.")
if hasattr(self, "update_statistics"):
index_details = indexes_utils.api_get_index(self, self.index_id)
self.test_data['columns'] = {'changed': [
{"is_exp": True, "col_num":
index_details.json['columns'][0]['col_num'],
"colname": self.column_name,
"nulls": False, "sort_order": False,
"statistics": "1000"}]}
self.data = self.test_data self.data = self.test_data
self.data['oid'] = self.index_id self.data['oid'] = self.index_id

View File

@ -117,6 +117,9 @@ def get_column_details(conn, idx, data, mode='properties', template_path=None):
row['attdef'].strip('"'), row['attdef'].strip('"'),
'collspcname': row['collnspname'], 'collspcname': row['collnspname'],
'op_class': row['opcname'], 'op_class': row['opcname'],
'col_num': row['attnum'],
'is_exp': row['is_exp'],
'statistics': row['statistics']
} }
# ASC/DESC and NULLS works only with btree indexes # ASC/DESC and NULLS works only with btree indexes
@ -245,6 +248,12 @@ def get_sql(conn, **kwargs):
raise ObjectGone(_('Could not find the index in the table.')) raise ObjectGone(_('Could not find the index in the table.'))
old_data = dict(res['rows'][0]) old_data = dict(res['rows'][0])
# Add column details for current index
old_data = get_column_details(conn, idx, old_data)
update_column_data, update_column = \
_get_column_details_to_update(old_data, data)
# Remove opening and closing bracket as we already have in jinja # Remove opening and closing bracket as we already have in jinja
# template. # template.
if 'using' in old_data and old_data['using'] is not None and \ if 'using' in old_data and old_data['using'] is not None and \
@ -263,7 +272,8 @@ def get_sql(conn, **kwargs):
sql = render_template( sql = render_template(
"/".join([template_path, 'update.sql']), "/".join([template_path, 'update.sql']),
data=data, o_data=old_data, conn=conn data=data, o_data=old_data, conn=conn,
update_column_data=update_column_data, update_column=update_column
) )
else: else:
sql = _get_create_sql(data, template_path, conn, mode, name, sql = _get_create_sql(data, template_path, conn, mode, name,
@ -353,3 +363,25 @@ def get_storage_params(amname):
"heap": [] "heap": []
} }
return storage_parameters[amname] return storage_parameters[amname]
def _get_column_details_to_update(old_data, data):
"""
This function returns the columns/expressions which need to update
:param old_data:
:param data:
:return:
"""
update_column_data = []
update_column = False
if 'columns' in data and 'changed' in data['columns']:
for index, col1 in enumerate(old_data['columns']):
for col2 in data['columns']['changed']:
if col1['col_num'] == col2['col_num'] and col1['statistics'] \
!= col2['statistics']:
update_column_data.append(col2)
update_column = True
break
return update_column_data, update_column

View File

@ -9,6 +9,8 @@ SELECT
END::text[] AS options, END::text[] AS options,
i.attnum, i.attnum,
pg_catalog.pg_get_indexdef(i.indexrelid, i.attnum, true) as attdef, pg_catalog.pg_get_indexdef(i.indexrelid, i.attnum, true) as attdef,
CASE WHEN pg_catalog.pg_get_indexdef(i.indexrelid, i.attnum, true) = a.attname THEN FALSE ELSE TRUE END AS is_exp,
a.attstattarget as statistics,
CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname, CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname,
op.oprname AS oprname, op.oprname AS oprname,
CASE WHEN length(nspc.nspname::text) > 0 AND length(coll.collname::text) > 0 THEN CASE WHEN length(nspc.nspname::text) > 0 AND length(coll.collname::text) > 0 THEN

View File

@ -3,7 +3,7 @@ CREATE{% if data.indisunique %} UNIQUE{% endif %} INDEX{% if add_not_exists_clau
ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %} ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %}
{% if mode == 'create' %} {% if mode == 'create' %}
({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.colname)}}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %} ({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{% if c.is_exp %}({{c.colname}}){% else %}{{conn|qtIdent(c.colname)}}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %}
{{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %} {{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %}
FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %}) FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %})
{% if data.include|length > 0 %} {% if data.include|length > 0 %}

View File

@ -3,7 +3,7 @@ CREATE{% if data.indisunique %} UNIQUE{% endif %} INDEX{% if add_not_exists_clau
ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %} ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %}
{% if mode == 'create' %} {% if mode == 'create' %}
({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.colname)}}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %} ({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{% if c.is_exp %}({{c.colname}}){% else %}{{conn|qtIdent(c.colname)}}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %}
{{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %} {{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %}
FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %}) FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %})
{% if data.include|length > 0 %} {% if data.include|length > 0 %}

View File

@ -9,6 +9,8 @@ SELECT
END::text[] AS options, END::text[] AS options,
i.attnum, i.attnum,
pg_catalog.pg_get_indexdef(i.indexrelid, i.attnum, true) as attdef, pg_catalog.pg_get_indexdef(i.indexrelid, i.attnum, true) as attdef,
CASE WHEN pg_catalog.pg_get_indexdef(i.indexrelid, i.attnum, true) = a.attname THEN FALSE ELSE TRUE END AS is_exp,
a.attstattarget as statistics,
CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname, CASE WHEN (o.opcdefault = FALSE) THEN o.opcname ELSE null END AS opcname,
op.oprname AS oprname, op.oprname AS oprname,
CASE WHEN length(nspc.nspname::text) > 0 AND length(coll.collname::text) > 0 THEN CASE WHEN length(nspc.nspname::text) > 0 AND length(coll.collname::text) > 0 THEN

View File

@ -3,7 +3,7 @@ CREATE{% if data.indisunique %} UNIQUE{% endif %} INDEX{% if add_not_exists_clau
ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %} ON {{conn|qtIdent(data.schema, data.table)}} {% if data.amname %}USING {{conn|qtIdent(data.amname)}}{% endif %}
{% if mode == 'create' %} {% if mode == 'create' %}
({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{{conn|qtIdent(c.colname)}}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %} ({% for c in data.columns %}{% if loop.index != 1 %}, {% endif %}{% if c.is_exp %}({{c.colname}}){% else %}{{conn|qtIdent(c.colname)}}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.op_class %}
{{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %} {{c.op_class}}{% endif %}{% if data.amname is defined %}{% if c.sort_order is defined and c.is_sort_nulls_applicable %}{% if c.sort_order %} DESC{% else %} ASC{% endif %}{% endif %}{% if c.nulls is defined and c.is_sort_nulls_applicable %} NULLS {% if c.nulls %}
FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %}) FIRST{% else %}LAST{% endif %}{% endif %}{% endif %}{% endfor %})
{% else %} {% else %}

View File

@ -85,3 +85,12 @@ ALTER TABLE IF EXISTS {{conn|qtIdent(data.schema, data.table)}}
{% if data.description is defined and o_data.description != data.description %} {% if data.description is defined and o_data.description != data.description %}
COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}} COMMENT ON INDEX {{conn|qtIdent(data.schema, data.name)}}
IS {{data.description|qtLiteral(conn)}};{% endif %} IS {{data.description|qtLiteral(conn)}};{% endif %}
{## Alter column statistics##}
{% if update_column %}
{% for col in update_column_data %}
ALTER INDEX IF EXISTS {{conn|qtIdent(data.schema, data.name)}}
ALTER COLUMN {{col.col_num}} SET STATISTICS {{col.statistics}};
{% endfor %}
{% endif %}

View File

@ -62,7 +62,7 @@ export default class PrivilegeRoleSchema extends BaseUISchema {
disabled : function(state) { disabled : function(state) {
return !( return !(
obj.nodeInfo && obj.nodeInfo &&
obj.nodeInfo.server.user.name == state['grantor'] obj.nodeInfo.server?.user?.name == state['grantor']
); );
}, },
}, },

View File

@ -133,8 +133,12 @@ const useStyles = makeStyles((theme)=>({
} }
})); }));
function DataTableHeader({headerGroups}) { function DataTableHeader({headerGroups, viewHelperProps, schema}) {
const classes = useStyles(); const classes = useStyles();
/* Using ref so that schema variable is not frozen in columns closure */
const schemaRef = useRef(schema);
const sortIcon = (isDesc) => { const sortIcon = (isDesc) => {
return isDesc ? ' 🔽' : ' 🔼'; return isDesc ? ' 🔽' : ' 🔼';
}; };
@ -142,21 +146,24 @@ function DataTableHeader({headerGroups}) {
<div className={classes.tableContentWidth}> <div className={classes.tableContentWidth}>
{headerGroups.map((headerGroup, hi) => ( {headerGroups.map((headerGroup, hi) => (
<div key={hi} {...headerGroup.getHeaderGroupProps()}> <div key={hi} {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column, ci) => ( {headerGroup.headers.map((column, ci) => {
<div key={ci} {...column.getHeaderProps()}> let {modeSupported} = column.field ? getFieldMetaData(column.field, schemaRef.current, {}, viewHelperProps) : {modeSupported: true};
<div {...(column.sortable ? column.getSortByToggleProps() : {})} className={clsx(classes.tableCell, classes.tableCellHeader)}> return( modeSupported &&
{column.render('Header')} <div key={ci} {...column.getHeaderProps()}>
<span> <div {...(column.sortable ? column.getSortByToggleProps() : {})} className={clsx(classes.tableCell, classes.tableCellHeader)}>
{column.isSorted ? sortIcon(column.isSortedDesc) : ''} {column.render('Header')}
</span> <span>
{column.isSorted ? sortIcon(column.isSortedDesc) : ''}
</span>
</div>
{!column.disableResizing &&
<div
{...column.getResizerProps()}
className={classes.resizer}
/>}
</div> </div>
{!column.disableResizing && );
<div })}
{...column.getResizerProps()}
className={classes.resizer}
/>}
</div>
))}
</div> </div>
))} ))}
</div> </div>
@ -165,9 +172,11 @@ function DataTableHeader({headerGroups}) {
DataTableHeader.propTypes = { DataTableHeader.propTypes = {
headerGroups: PropTypes.array.isRequired, headerGroups: PropTypes.array.isRequired,
viewHelperProps: PropTypes.object.isRequired,
schema: CustomPropTypes.schemaUI.isRequired,
}; };
function DataTableRow({index, row, totalRows, isResizing, isHovered, schema, schemaRef, accessPath, moveRow, setHoverIndex}) { function DataTableRow({index, row, totalRows, isResizing, isHovered, schema, schemaRef, accessPath, moveRow, setHoverIndex, viewHelperProps}) {
const classes = useStyles(); const classes = useStyles();
const [key, setKey] = useState(false); const [key, setKey] = useState(false);
const depListener = useContext(DepListenerContext); const depListener = useContext(DepListenerContext);
@ -282,13 +291,16 @@ function DataTableRow({index, row, totalRows, isResizing, isHovered, schema, sch
> >
{row.cells.map((cell, ci) => { {row.cells.map((cell, ci) => {
let classNames = [classes.tableCell]; let classNames = [classes.tableCell];
let {modeSupported} = cell.column.field? getFieldMetaData(cell.column.field, schemaRef.current, {}, viewHelperProps) : {modeSupported: true};
if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) { if(typeof(cell.column.id) == 'string' && cell.column.id.startsWith('btn-')) {
classNames.push(classes.btnCell); classNames.push(classes.btnCell);
} }
if(cell.column.id == 'btn-edit' && row.isExpanded) { if(cell.column.id == 'btn-edit' && row.isExpanded) {
classNames.push(classes.expandedIconCell); classNames.push(classes.expandedIconCell);
} }
return ( return (modeSupported &&
<div ref={cell.column.id == 'btn-reorder' ? dragHandleRef : null} key={ci} {...cell.getCellProps()} className={clsx(classNames)}> <div ref={cell.column.id == 'btn-reorder' ? dragHandleRef : null} key={ci} {...cell.getCellProps()} className={clsx(classNames)}>
{cell.render('Cell', { {cell.render('Cell', {
reRenderRow: ()=>{setKey((currKey)=>!currKey);} reRenderRow: ()=>{setKey((currKey)=>!currKey);}
@ -490,13 +502,13 @@ export default function DataGridView({
/* Make sure to take the latest field info from schema */ /* Make sure to take the latest field info from schema */
field = _.find(schemaRef.current.fields, (f)=>f.id==field.id) || field; field = _.find(schemaRef.current.fields, (f)=>f.id==field.id) || field;
let {editable, disabled} = getFieldMetaData(field, schemaRef.current, row.original || {}, viewHelperProps); let {editable, disabled, modeSupported} = getFieldMetaData(field, schemaRef.current, row.original || {}, viewHelperProps);
if(_.isUndefined(field.cell)) { if(_.isUndefined(field.cell)) {
console.error('cell is required ', field); console.error('cell is required ', field);
} }
return <MappedCellControl rowIndex={row.index} value={value} return modeSupported && <MappedCellControl rowIndex={row.index} value={value}
row={row.original} {...field} row={row.original} {...field}
readonly={!editable} readonly={!editable}
disabled={disabled} disabled={disabled}
@ -631,14 +643,14 @@ export default function DataGridView({
/>} />}
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
<div {...getTableProps(()=>({style: {minWidth: 'unset'}}))} className={classes.table}> <div {...getTableProps(()=>({style: {minWidth: 'unset'}}))} className={classes.table}>
<DataTableHeader headerGroups={headerGroups} /> <DataTableHeader headerGroups={headerGroups} viewHelperProps={viewHelperProps} schema={schema} />
<div {...getTableBodyProps()} className={classes.tableContentWidth}> <div {...getTableBodyProps()} className={classes.tableContentWidth}>
{rows.map((row, i) => { {rows.map((row, i) => {
prepareRow(row); prepareRow(row);
return <React.Fragment key={row.index}> return <React.Fragment key={row.index}>
<DataTableRow index={i} row={row} totalRows={rows.length} isResizing={isResizing} <DataTableRow index={i} row={row} totalRows={rows.length} isResizing={isResizing}
schema={schemaRef.current} schemaRef={schemaRef} accessPath={accessPath.concat([row.index])} schema={schemaRef.current} schemaRef={schemaRef} accessPath={accessPath.concat([row.index])}
moveRow={moveRow} isHovered={i == hoverIndex} setHoverIndex={setHoverIndex} /> moveRow={moveRow} isHovered={i == hoverIndex} setHoverIndex={setHoverIndex} viewHelperProps={viewHelperProps}/>
{props.canEdit && row.isExpanded && {props.canEdit && row.isExpanded &&
<FormView value={row.original} viewHelperProps={viewHelperProps} dataDispatch={dataDispatch} <FormView value={row.original} viewHelperProps={viewHelperProps} dataDispatch={dataDispatch}
schema={schemaRef.current} accessPath={accessPath.concat([row.index])} isNested={true} className={classes.expandedForm} schema={schemaRef.current} accessPath={accessPath.concat([row.index])} isNested={true} className={classes.expandedForm}

View File

@ -10,121 +10,57 @@
import '../helper/enzyme.helper'; import '../helper/enzyme.helper';
import { createMount } from '@material-ui/core/test-utils'; import { createMount } from '@material-ui/core/test-utils';
import * as nodeAjax from '../../../pgadmin/browser/static/js/node_ajax'; import * as nodeAjax from '../../../pgadmin/browser/static/js/node_ajax';
import IndexSchema, { getColumnSchema } from '../../../pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.ui'; import BaseUISchema from '../../../pgadmin/static/js/SchemaView/base_schema.ui';
import IndexSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/static/js/index.ui';
import {genericBeforeEach, getCreateView, getEditView, getPropertiesView} from '../genericFunctions'; import {genericBeforeEach, getCreateView, getEditView, getPropertiesView} from '../genericFunctions';
class SchemaInColl extends BaseUISchema {
constructor(indexSchemaObj) {
super();
this.indexSchemaObj = indexSchemaObj;
}
get baseFields() {
return [{
id: 'collection', label: '', type: 'collection',
schema: this.indexSchemaObj,
editable: false,
canAdd: true, canEdit: false, canDelete: true, hasRole: true,
columns : ['name', 'consrc'],
}];
}
}
function getFieldDepChange(schema, id) {
return _.find(schema.fields, (f)=>f.id==id)?.depChange;
}
describe('IndexSchema', ()=>{ describe('IndexSchema', ()=>{
let mount; let mount;
let indexSchemaObj;
describe('column schema describe', () => {
let columnSchemaObj = getColumnSchema({}, {server: {user: {name: 'postgres'}}}, {});
it('column schema collection', ()=>{
spyOn(nodeAjax, 'getNodeAjaxOptions').and.returnValue([]);
spyOn(nodeAjax, 'getNodeListByName').and.returnValue([]);
mount(getCreateView(columnSchemaObj));
mount(getEditView(columnSchemaObj, getInitData));
});
it('column schema colname editable', ()=>{
columnSchemaObj._top = {
_sessData: { amname: 'btree' }
};
let cell = _.find(columnSchemaObj.fields, (f)=>f.id=='op_class').cell;
cell();
});
it('column schema sort_order depChange', ()=>{
let topState = { amname: 'btree' };
let depChange = _.find(columnSchemaObj.fields, (f)=>f.id=='sort_order').depChange;
let state = { sort_order: true };
depChange(state, {}, topState, { oldState: { sort_order: false } });
state.sort_order = false;
topState.amname = 'abc';
depChange(state, {}, topState, { oldState: { sort_order: false } });
expect(state.is_sort_nulls_applicable).toBe(false);
});
it('column schema sort_order editable', ()=>{
columnSchemaObj._top = {
_sessData: { amname: 'btree' }
};
let state = {};
spyOn(columnSchemaObj, 'inSchemaWithModelCheck').and.returnValue(true);
let editable = _.find(columnSchemaObj.fields, (f)=>f.id=='sort_order').editable;
let status = editable(state);
expect(status).toBe(false);
spyOn(columnSchemaObj, 'inSchemaWithModelCheck').and.returnValue(false);
status = editable(state);
expect(status).toBe(true);
columnSchemaObj._top._sessData.amname = 'abc';
status = editable(state);
expect(status).toBe(false);
});
it('column schema nulls editable', ()=>{
columnSchemaObj._top = {
_sessData: { amname: 'btree' }
};
let state = {};
spyOn(columnSchemaObj, 'inSchemaWithModelCheck').and.returnValue(true);
let editable = _.find(columnSchemaObj.fields, (f)=>f.id=='nulls').editable;
let status = editable(state);
expect(status).toBe(false);
spyOn(columnSchemaObj, 'inSchemaWithModelCheck').and.returnValue(false);
status = editable(state);
expect(status).toBe(true);
columnSchemaObj._top._sessData.amname = 'abc';
status = editable(state);
expect(status).toBe(false);
});
it('column schema setOpClassTypes', ()=>{
columnSchemaObj._top = {
_sessData: { amname: 'btree' }
};
let options = [];
columnSchemaObj.op_class_types = [];
let status = columnSchemaObj.setOpClassTypes(options);
expect(status).toEqual([]);
columnSchemaObj.op_class_types = [];
options.push({label: '', value: ''});
columnSchemaObj.setOpClassTypes(options);
expect(columnSchemaObj.op_class_types.length).toBe(1);
});
});
let indexSchemaObj = new IndexSchema(
()=>getColumnSchema({}, {server: {user: {name: 'postgres'}}}, {}),
{
tablespaceList: ()=>[],
amnameList : ()=>[{label:'abc', value:'abc'}],
columnList: ()=>[{label:'abc', value:'abc'}],
},
{
node_info: {'server': { 'version': 110000} }
},
{
amname: 'btree'
}
);
let getInitData = ()=>Promise.resolve({}); let getInitData = ()=>Promise.resolve({});
/* Use createMount so that material ui components gets the required context */ /* Use createMount so that material ui components gets the required context */
/* https://material-ui.com/guides/testing/#api */ /* https://material-ui.com/guides/testing/#api */
beforeAll(()=>{ beforeAll(()=>{
mount = createMount(); mount = createMount();
spyOn(nodeAjax, 'getNodeAjaxOptions').and.returnValue(Promise.resolve([]));
spyOn(nodeAjax, 'getNodeListByName').and.returnValue(Promise.resolve([]));
indexSchemaObj = new IndexSchema(
{
tablespaceList: ()=>[],
amnameList : ()=>[{label:'abc', value:'abc'}],
columnList: ()=>[{label:'abc', value:'abc'}],
collationList: ()=>[{label:'abc', value:'abc'}],
opClassList: ()=>[{label:'abc', value:'abc'}]
},
{
node_info: {'server': { 'version': 110000} }
},
{
amname: 'btree'
}
);
}); });
afterAll(() => { afterAll(() => {
@ -147,12 +83,150 @@ describe('IndexSchema', ()=>{
mount(getPropertiesView(indexSchemaObj, getInitData)); mount(getPropertiesView(indexSchemaObj, getInitData));
}); });
it('create collection', ()=>{
let schemaCollObj = new SchemaInColl(indexSchemaObj);
let ctrl = mount(getCreateView(schemaCollObj));
/* Make sure you hit every corner */
ctrl.find('DataGridView').at(0).find('PgIconButton[data-test="add-row"]').find('button').simulate('click');
});
it('changeColumnOptions', ()=>{
spyOn(indexSchemaObj.indexHeaderSchema, 'changeColumnOptions').and.callThrough();
let columns = [{label: 'label', value: 'value'}];
indexSchemaObj.changeColumnOptions(columns);
expect(indexSchemaObj.indexHeaderSchema.changeColumnOptions).toHaveBeenCalledWith(columns);
});
describe('IndexColHeaderSchema', ()=>{
it('getNewData', ()=>{
indexSchemaObj.indexHeaderSchema.columnOptions = [
{label: 'id', value: 'id'},
{label: 'name', value: 'name'}
];
spyOn(indexSchemaObj.indexColumnSchema, 'getNewData');
indexSchemaObj.indexHeaderSchema.getNewData({
is_exp: false,
colname: 'id',
expression: null,
});
expect(indexSchemaObj.indexColumnSchema.getNewData).toHaveBeenCalledWith({
is_exp: false,
colname: 'id',
});
indexSchemaObj.indexHeaderSchema.getNewData({
is_exp: true,
colname: null,
expression: 'abc',
});
expect(indexSchemaObj.indexColumnSchema.getNewData).toHaveBeenCalledWith({
is_exp: true,
colname: 'abc',
});
});
});
describe('IndexColumnSchema', ()=>{
it('column schema colname editable', ()=>{
indexSchemaObj.indexColumnSchema._top = {
_sessData: { amname: 'btree' }
};
let cell = _.find(indexSchemaObj.indexColumnSchema.fields, (f)=>f.id=='op_class').cell;
cell();
});
it('column schema sort_order depChange', ()=>{
let topState = { amname: 'btree' };
let depChange = _.find(indexSchemaObj.indexColumnSchema.fields, (f)=>f.id=='sort_order').depChange;
let state = { sort_order: true };
depChange(state, {}, topState, { oldState: { sort_order: false } });
state.sort_order = false;
topState.amname = 'abc';
depChange(state, {}, topState, { oldState: { sort_order: false } });
expect(state.is_sort_nulls_applicable).toBe(false);
});
it('column schema sort_order editable', ()=>{
indexSchemaObj.indexColumnSchema._top = {
_sessData: { amname: 'btree' }
};
let state = {};
spyOn(indexSchemaObj.indexColumnSchema, 'inSchemaWithModelCheck').and.returnValue(true);
let editable = _.find(indexSchemaObj.indexColumnSchema.fields, (f)=>f.id=='sort_order').editable;
let status = editable(state);
expect(status).toBe(false);
spyOn(indexSchemaObj.indexColumnSchema, 'inSchemaWithModelCheck').and.returnValue(false);
status = editable(state);
expect(status).toBe(true);
indexSchemaObj.indexColumnSchema._top._sessData.amname = 'abc';
status = editable(state);
expect(status).toBe(false);
});
it('column schema nulls editable', ()=>{
indexSchemaObj.indexColumnSchema._top = {
_sessData: { amname: 'btree' }
};
let state = {};
spyOn(indexSchemaObj.indexColumnSchema, 'inSchemaWithModelCheck').and.returnValue(true);
let editable = _.find(indexSchemaObj.indexColumnSchema.fields, (f)=>f.id=='nulls').editable;
let status = editable(state);
expect(status).toBe(false);
spyOn(indexSchemaObj.indexColumnSchema, 'inSchemaWithModelCheck').and.returnValue(false);
status = editable(state);
expect(status).toBe(true);
indexSchemaObj.indexColumnSchema._top._sessData.amname = 'abc';
status = editable(state);
expect(status).toBe(false);
});
it('column schema setOpClassTypes', ()=>{
indexSchemaObj.indexColumnSchema._top = {
_sessData: { amname: 'btree' }
};
let options = [];
indexSchemaObj.indexColumnSchema.op_class_types = [];
let status = indexSchemaObj.indexColumnSchema.setOpClassTypes(options);
expect(status).toEqual([]);
indexSchemaObj.indexColumnSchema.op_class_types = [];
options.push({label: '', value: ''});
indexSchemaObj.indexColumnSchema.setOpClassTypes(options);
expect(indexSchemaObj.indexColumnSchema.op_class_types.length).toBe(1);
});
});
it('depChange', ()=>{
let state = {};
expect(getFieldDepChange(indexSchemaObj, 'description')(state)).toEqual({
comment: '',
});
});
it('columns formatter', ()=>{
let formatter = _.find(indexSchemaObj.fields, (f)=>f.id=='columns').cell().controlProps.formatter;
expect(formatter.fromRaw([{
colname: 'lid',
},{
colname: 'rid',
}])).toBe('lid, rid');
expect(formatter.fromRaw([])).toBe('');
});
it('validate', ()=>{ it('validate', ()=>{
let state = { columns: [] }; let state = { columns: [] };
let setError = jasmine.createSpy('setError'); let setError = jasmine.createSpy('setError');
indexSchemaObj.validate(state, setError); indexSchemaObj.validate(state, setError);
expect(setError).toHaveBeenCalledWith('columns', 'You must specify at least one column.'); expect(setError).toHaveBeenCalledWith('columns', 'You must specify at least one column/expression.');
state.columns.push({}); state.columns.push({});
let status = indexSchemaObj.validate(state, setError); let status = indexSchemaObj.validate(state, setError);