Added search object functionality. Fixes #2172

This commit is contained in:
Aditya Toshniwal
2020-04-06 17:33:07 +05:30
committed by Akshay Joshi
parent f77aa3284f
commit e1f990190e
57 changed files with 5968 additions and 494 deletions

View File

@@ -64,6 +64,8 @@ display. To open the *Preferences* dialog, select *Preferences* from the *File*
for the dialog. You can access additional Postgres help by navigating through
the *Help* menu, and selecting the name of the resource that you wish to open.
You can search for objects in the database using the :ref:`Search objects <search_objects>`
.. toctree::
:maxdepth: 2
@@ -74,6 +76,7 @@ the *Help* menu, and selecting the name of the resource that you wish to open.
tree_control
preferences
keyboard_shortcuts
search_objects
Before using pgAdmin to manage objects that reside on a server, you must define a
connection to the server; for more information please see *Connecting to a Server*

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -9,6 +9,7 @@ This release contains a number of bug fixes and new features since the release o
New features
************
| `Issue #2172 <https://redmine.postgresql.org/issues/2172>`_ - Added search object functionality.
| `Issue #2186 <https://redmine.postgresql.org/issues/2186>`_ - Added LDAP authentication support.
| `Issue #5184 <https://redmine.postgresql.org/issues/5184>`_ - Added support for parameter toast_tuple_target and parallel_workers of the table.
| `Issue #5264 <https://redmine.postgresql.org/issues/5264>`_ - Added support of Packages, Sequences and Synonyms to the Schema Diff.

View File

@@ -0,0 +1,34 @@
.. _search_objects:
***********************
`Search objects`:index:
***********************
.. image:: images/search_objects.png
:alt: Search objects dialog
:align: center
With this dialog, you can search for almost any kind of objects in a
database.
You can access it by right clicking a database or any of its child nodes
and select "Search objects". You can also access it by hitting the
shortcut (default ALT+SHIFT+S).
The minimum pattern length are 3 characters. The search performed is
non-casesensitive and will find all objets whose name contains the pattern.
You can only search for object names.
The result is presented in the grid with object name, object type and
the object tree path in the :ref:`browser <tree_control>`. You can double
click on a result row to select the object in the
:ref:`browser <tree_control>`. If the object is greyed out, this means that you
have not enabled those object types in the :ref:`preferences <preferences>`,
so you can't double click on it.
You can filter based on a particular object type by selecting one from the
object type dropdown. If the search button is hit when one of the object type
is selected then only those types will be fetch from the database.
An object type will not be visible in the dropdown if the database server
does not support it or if it is not enabled from the
:ref:`preferences <preferences>`.

View File

@@ -18,4 +18,6 @@ the selected browser node.
* Use the :ref:`View Data <editgrid>` button to view/edit the data stored in a
selected table.
* Use the :ref:`Filtered Rows <viewdata_filter>` button to access the Data Filter popup
to apply a filter to a set of data for viewing/editing.
to apply a filter to a set of data for viewing/editing.
* Use the :ref:`Search objects <search_objects>` button to access the search objects
dialog. It helps you search any database object.

View File

@@ -249,6 +249,21 @@ def register_browser_preferences(self):
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'sub_menu_search_objects',
gettext('Search objects'),
'keyboardshortcut',
{
'alt': True,
'shift': True,
'control': False,
'key': {'key_code': 83, 'char': 's'}
},
category_label=gettext('Keyboard shortcuts'),
fields=fields
)
self.preference.register(
'keyboard_shortcuts',
'sub_menu_create',

View File

@@ -24,7 +24,7 @@ define('pgadmin.node.extension', [
pgAdmin.Browser.Nodes['coll-extension'] =
pgAdmin.Browser.Collection.extend({
node: 'extension',
label: gettext('Extension'),
label: gettext('Extensions'),
type: 'coll-extension',
columns: ['name', 'owner', 'comment'],
});

View File

@@ -0,0 +1,11 @@
SELECT
nsp.oid, nspname AS name
FROM
pg_namespace nsp
WHERE nspparent = {{scid}}::oid
{% if pkgid %}
AND nsp.oid = {{pkgid}}::oid
{% endif %}
AND nspobjecttype = 0
AND nspcompoundtrigger = false
ORDER BY nspname;

View File

@@ -54,8 +54,8 @@ class IndexConstraintModule(ConstraintTypeModule):
initialized.
"""
NODE_TYPE = 'Index constraint'
COLLECTION_LABEL = _('index_constraint')
NODE_TYPE = 'index_constraint'
COLLECTION_LABEL = _('Index constraint')
def __init__(self, *args, **kwargs):
"""

View File

@@ -29,8 +29,11 @@ from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
def backend_supported(module, manager, **kwargs):
if 'tid' in kwargs and CollectionNodeModule.BackendSupported(
module, manager, **kwargs):
if CollectionNodeModule.BackendSupported(module, manager, **kwargs):
if 'tid' not in kwargs:
return True
conn = manager.connection(did=kwargs['did'])
template_path = 'partitions/sql/{0}/#{0}#{1}#'.format(

View File

@@ -21,19 +21,19 @@ else:
class TestBackendSupport(BaseTestGenerator):
scenarios = [
('when tid is not present in arguments, should return None and no '
'query should be done',
('when tid is not present in arguments, but server version'
'is supported then return True',
dict(
manager=dict(
server_type="",
version=""
server_type="pg",
version="100000"
),
input_arguments=dict(did=432),
collection_node_active=True,
connection_execution_return_value=[],
expected_return_value=None,
expected_return_value=True,
expect_error_response=False,
expected_number_calls_on_render_template=0
)),

View File

@@ -9,6 +9,9 @@
(SELECT 1 FROM pg_class WHERE relname = 'tables' AND
relnamespace = {{ tbl }}.oid LIMIT 1))
{%- endmacro %}
{% macro IS_CATALOG_SCHEMA(schema_col_name) -%}
{{ schema_col_name }} IN ('pg_catalog', 'pgagent', 'information_schema')
{%- endmacro %}
{% macro LABELS(tbl, _) -%}
CASE {{ tbl }}.nspname
WHEN 'pg_catalog' THEN '{{ _( 'PostgreSQL Catalog' ) }} (pg_catalog)'
@@ -17,9 +20,24 @@
ELSE {{ tbl }}.nspname
END AS name
{%- endmacro %}
{% macro LABELS_SCHEMACOL(schema_col_name, _) -%}
CASE {{ schema_col_name }}
WHEN 'pg_catalog' THEN '{{ _( 'PostgreSQL Catalog' ) }} (pg_catalog)'
WHEN 'pgagent' THEN '{{ _( 'pgAgent Job Scheduler' ) }} (pgagent)'
WHEN 'information_schema' THEN '{{ _( 'ANSI' ) }} (information_schema)'
ELSE {{ schema_col_name }}
END
{%- endmacro %}
{% macro DB_SUPPORT(tbl) -%}
CASE
WHEN {{ tbl }}.nspname = ANY('{information_schema}')
THEN false
ELSE true END
{%- endmacro %}
{% macro DB_SUPPORT_SCHEMACOL(schema_col_name) -%}
CASE
WHEN {{ schema_col_name }} = ANY('{information_schema}')
THEN false
ELSE true END
{%- endmacro %}

View File

@@ -13,6 +13,9 @@
(SELECT 1 FROM pg_proc
WHERE pronamespace = {{ tbl }}.oid and proname = 'run_job' LIMIT 1))
{%- endmacro %}
{% macro IS_CATALOG_SCHEMA(schema_col_name) -%}
{{ schema_col_name }} IN ('pg_catalog', 'pgagent', 'information_schema', 'dbo', 'sys', 'dbms_job_procedure')
{%- endmacro %}
{% macro LABELS(tbl, _) -%}
CASE {{ tbl }}.nspname
WHEN 'pg_catalog' THEN '{{ _( 'PostgreSQL Catalog' ) }} (pg_catalog)'
@@ -23,9 +26,25 @@
ELSE {{ tbl }}.nspname
END AS name
{%- endmacro %}
{% macro DB_SUPPORT(tbl) -%}
{% macro LABELS_SCHEMACOL(schema_col_name, _) -%}
CASE {{ schema_col_name }}
WHEN 'pg_catalog' THEN '{{ _( 'PostgreSQL Catalog' ) }} (pg_catalog)'
WHEN 'pgagent' THEN '{{ _( 'pgAgent Job Scheduler' ) }} (pgagent)'
WHEN 'information_schema' THEN '{{ _( 'ANSI' ) }} (information_schema)'
WHEN 'dbo' THEN 'Redmond (dbo)'
WHEN 'sys' THEN 'Redwood (sys)'
ELSE {{ schema_col_name }}
END
{%- endmacro %}
{% macro DB_SUPPORT(tbl, schema_col_name) -%}
CASE
WHEN {{ tbl }}.nspname = ANY('{information_schema,sys,dbo}')
THEN false
ELSE true END
{%- endmacro %}
{% macro DB_SUPPORT_SCHEMACOL(schema_col_name) -%}
CASE
WHEN {{ schema_col_name }} = ANY('{information_schema,sys,dbo}')
THEN false
ELSE true END
{%- endmacro %}

View File

@@ -18,6 +18,7 @@ define('pgadmin.node.role', [
pgAdmin.Browser.Nodes['coll-role'] =
pgAdmin.Browser.Collection.extend({
node: 'role',
label: gettext('Login/Group Roles'),
type: 'coll-role',
columns: [
'rolname', 'rolvaliduntil', 'rolconnlimit', 'rolcanlogin',

View File

@@ -51,14 +51,23 @@ define([
}]);
// show query tool only in context menu of supported nodes.
if (pgAdmin.DataGrid && pgAdmin.unsupported_nodes) {
if (_.indexOf(pgAdmin.unsupported_nodes, this.type) == -1) {
if (pgAdmin.unsupported_nodes && _.indexOf(pgAdmin.unsupported_nodes, this.type) == -1) {
if ((this.type == 'database' && this.allowConn) || this.type != 'database') {
pgAdmin.Browser.add_menus([{
name: 'show_query_tool', node: this.type, module: this,
name: 'show_query_tool', node: this.type, module: pgAdmin.DataGrid,
applies: ['context'], callback: 'show_query_tool',
priority: 998, label: gettext('Query Tool...'),
icon: 'pg-font-icon icon-query-tool',
}]);
// show search objects same as query tool
pgAdmin.Browser.add_menus([{
name: 'search_objects', node: this.type, module: pgAdmin.SearchObjects,
applies: ['context'], callback: 'show_search_objects',
priority: 997, label: gettext('Search Objects...'),
icon: 'fa fa-search',
}]);
}
}
},

View File

@@ -34,6 +34,7 @@ _.extend(pgBrowser.keyboardNavigation, {
'tabbed_panel_forward': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'tabbed_panel_forward').value),
'sub_menu_query_tool': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_query_tool').value),
'sub_menu_view_data': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_view_data').value),
'sub_menu_search_objects': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_search_objects').value),
'sub_menu_properties': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_properties').value),
'sub_menu_create': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_create').value),
'sub_menu_delete': commonUtils.parseShortcutValue(pgBrowser.get_preference('browser', 'sub_menu_delete').value),
@@ -55,6 +56,7 @@ _.extend(pgBrowser.keyboardNavigation, {
'bindLeftTree': {'shortcuts': this.keyboardShortcut.left_tree_shortcut}, // Main menu,
'bindSubMenuQueryTool': {'shortcuts': this.keyboardShortcut.sub_menu_query_tool}, // Sub menu - Open Query Tool,
'bindSubMenuViewData': {'shortcuts': this.keyboardShortcut.sub_menu_view_data}, // Sub menu - Open View Data,
'bindSubMenuSearchObjects': {'shortcuts': this.keyboardShortcut.sub_menu_search_objects}, // Sub menu - Open search objects,
'bindSubMenuProperties': {'shortcuts': this.keyboardShortcut.sub_menu_properties}, // Sub menu - Edit Properties,
'bindSubMenuCreate': {'shortcuts': this.keyboardShortcut.sub_menu_create}, // Sub menu - Create Object,
'bindSubMenuDelete': {'shortcuts': this.keyboardShortcut.sub_menu_delete}, // Sub menu - Delete object,
@@ -261,6 +263,15 @@ _.extend(pgBrowser.keyboardNavigation, {
// Call data grid method to render view data
pgAdmin.DataGrid.show_data_grid({'mnuid': 1}, tree.i);
},
bindSubMenuSearchObjects: function() {
const tree = this.getTreeDetails();
if (!tree.d)
return;
// Call data grid method to render view data
pgAdmin.SearchObjects.show_search_objects('', tree.i);
},
bindSubMenuProperties: function() {
const tree = this.getTreeDetails();

View File

@@ -177,6 +177,14 @@ define('pgadmin.browser.node', [
// Show query tool only in context menu of supported nodes.
if (_.indexOf(pgAdmin.unsupported_nodes, self.type) == -1) {
let enable = function(itemData) {
if (itemData._type == 'database' && itemData.allowConn)
return true;
else if (itemData._type != 'database')
return true;
else
return false;
};
pgAdmin.Browser.add_menus([{
name: 'show_query_tool',
node: self.type,
@@ -186,14 +194,15 @@ define('pgadmin.browser.node', [
priority: 998,
label: gettext('Query Tool...'),
icon: 'pg-font-icon icon-query-tool',
enable: function(itemData) {
if (itemData._type == 'database' && itemData.allowConn)
return true;
else if (itemData._type != 'database')
return true;
else
return false;
},
enable: enable,
}]);
// show search objects same as query tool
pgAdmin.Browser.add_menus([{
name: 'search_objects', node: self.type, module: pgAdmin.SearchObjects,
applies: ['context'], callback: 'show_search_objects',
priority: 997, label: gettext('Search Objects...'),
icon: 'fa fa-search', enable: enable,
}]);
}

View File

@@ -46,6 +46,16 @@ let _defaultToolBarButtons = [
parentClass: 'pg-toolbar-btn btn-secondary',
enabled: false,
},
{
label: gettext('Search objects'),
ariaLabel: gettext('Search objects'),
btnClass: 'fa fa-search',
text: '',
toggled: false,
toggleClass: '',
parentClass: 'pg-toolbar-btn btn-secondary',
enabled: false,
},
];
// Place holder for non default tool bar buttons.
@@ -92,6 +102,8 @@ export function initializeToolbar(panel, wcDocker) {
pgAdmin.DataGrid.show_data_grid({mnuid: 3}, pgAdmin.Browser.tree.selected());
else if ('name' in data && data.name === gettext('Filtered Rows'))
pgAdmin.DataGrid.show_filtered_row({mnuid: 4}, pgAdmin.Browser.tree.selected());
else if ('name' in data && data.name === gettext('Search objects'))
pgAdmin.SearchObjects.show_search_objects('', pgAdmin.Browser.tree.selected());
});
}

View File

@@ -11,7 +11,7 @@
{% block init_script %}
try {
require(
['sources/generated/app.bundle', 'sources/generated/codemirror', 'sources/generated/browser_nodes'],
['sources/generated/app.bundle', 'sources/generated/codemirror', 'sources/generated/browser_nodes', 'sources/generated/slickgrid'],
function() {
},
function() {

View File

@@ -8,7 +8,6 @@
//////////////////////////////////////////////////////////////
import 'slickgrid/lib/jquery.event.drag-2.3.0';
import 'slickgrid/lib/jquery-ui-1.11.3';
import 'slickgrid/slick.core';
import 'slickgrid/slick.grid';
import 'slickgrid/slick.dataview';
@@ -21,5 +20,6 @@ import 'slickgrid/plugins/slick.cellrangeselector';
import 'slickgrid/plugins/slick.checkboxselectcolumn';
import 'slickgrid/plugins/slick.rowselectionmodel';
import 'sources/slickgrid/custom_header_buttons';
import 'sources/slickgrid/plugins/slick.autocolumnsize';
export default window.Slick;

View File

@@ -5,18 +5,17 @@
@import '~tempusdominus-bootstrap-4/build/css/tempusdominus-bootstrap-4.css';
@import '~bootstrap4-toggle/css/bootstrap4-toggle.css';
@import '~backgrid-filter/backgrid-filter.css';
@import '~slickgrid/css/select2.css';
@import '~jquery-contextmenu/dist/jquery.contextMenu.css';
@import '~webcabin-docker/Build/wcDocker.css';
@import '~acitree/css/aciTree.css';
@import '~leaflet/dist/leaflet.css';
@import '../../../node_modules/select2/dist/css/select2.css';
@import '~codemirror/lib/codemirror.css';
@import '~codemirror/addon/dialog/dialog.css';
@import '~codemirror/addon/scroll/simplescrollbars.css';
@import '~slickgrid/slick.grid.css';
@import '~slickgrid/slick-default-theme.css';
@import '~slickgrid/css/smoothness/jquery-ui-1.11.3.custom.css';
@import '../vendor/backgrid/backgrid.css';

View File

@@ -271,7 +271,8 @@ define([
let container = $(self.elements.footer);
commonUtils.findAndSetFocus(container.find('button:not([disabled]):last'));
}
}); });
});
});
this.set('onresize', alertifyDialogStartResizing.bind(this, true));
this.set('onresized', alertifyDialogResized.bind(this, true));
this.set('onmaximized', alertifyDialogResized);

View File

@@ -80,6 +80,39 @@ export class Dialog {
return serverInformation;
}
retrieveAncestorOfTypeDatabase(item) {
let databaseInfo = null;
let aciTreeItem = item || this.pgBrowser.treeMenu.selected();
let treeNode = this.pgBrowser.treeMenu.findNodeByDomElement(aciTreeItem);
if (treeNode) {
if(treeNode.getData()._type === 'database') {
databaseInfo = treeNode.getData();
} else {
let nodeData = null;
treeNode.ancestorNode(
(node) => {
nodeData = node.getData();
if(nodeData._type === 'database') {
databaseInfo = nodeData;
return true;
}
return false;
}
);
}
}
if (databaseInfo === null) {
this.alertify.alert(
gettext(this.errorAlertTitle),
gettext('Please select a database or its child node from the browser.')
);
}
return databaseInfo;
}
hasBinariesConfiguration(serverInformation) {
const module = 'paths';
let preference_name = 'pg_bin_dir';

View File

@@ -9,6 +9,7 @@
import * as BackupDialog from '../../../tools/backup/static/js/backup_dialog_wrapper';
import {RestoreDialogWrapper} from '../../../tools/restore/static/js/restore_dialog_wrapper';
import SearchObjectsDialogWrapper from '../../../tools/search_objects/static/js/search_objects_dialog_wrapper';
export class DialogFactory {
constructor(pgBrowser, $,
@@ -25,6 +26,8 @@ export class DialogFactory {
create(dialogTitle, typeOfDialog) {
if (typeOfDialog === 'restore') {
return this.createRestoreDialog(dialogTitle, typeOfDialog);
} else if (typeOfDialog === 'search_objects') {
return this.createSearchObjectsDialog(dialogTitle, typeOfDialog);
} else {
return this.createBackupDialog(dialogTitle, typeOfDialog);
}
@@ -49,4 +52,14 @@ export class DialogFactory {
this.dialogModel,
this.backform);
}
createSearchObjectsDialog(dialogTitle, typeOfDialog) {
return new SearchObjectsDialogWrapper(
this.dialogContainerSelector, dialogTitle, typeOfDialog,
this.jquery,
this.pgBrowser,
this.alertify,
this.dialogModel,
this.backform);
}
}

View File

@@ -58,7 +58,11 @@ export class DialogWrapper {
let backform_tab = $(alertifyDialog.elements.body).find('.backform-tab');
backform_tab.attr('tabindex', -1);
this.pgBrowser.keyboardNavigation.getDialogTabNavigator($(alertifyDialog.elements.dialog));
const container = backform_tab.find('.tab-content:first > .tab-pane.active:first');
let container = backform_tab.find('.tab-content:first > .tab-pane.active:first');
if(container.length === 0 && alertifyDialog.elements.content.innerHTML) {
container = $(alertifyDialog.elements.content);
}
commonUtils.findAndSetFocus(container);
}

View File

@@ -98,7 +98,7 @@
function getTemplateWidth(rowEl, template) {
var cell = $(rowEl.find('.slick-cell'));
cell.append(template);
$(cell).find('*').css('position', 'relative');
cell.find('*').css('position', 'relative');
return cell.outerWidth() + 1;
}
@@ -128,7 +128,7 @@
'text-overflow': 'initial',
'white-space': 'nowrap',
});
var gridCanvas = $container.find('.grid-canvas');
var gridCanvas = $container.find('.grid-canvas').first();
$(gridCanvas).append(rowEl);
return rowEl;
}

View File

@@ -50,17 +50,50 @@ export class TreeNode {
}
reload(tree) {
this.unload(tree);
tree.aciTreeApi.setInode(this.domNode);
tree.aciTreeApi.deselect(this.domNode);
setTimeout(() => {
tree.selectNode(this.domNode);
}, 0);
return new Promise((resolve)=>{
this.unload(tree)
.then(()=>{
tree.aciTreeApi.setInode(this.domNode);
tree.aciTreeApi.deselect(this.domNode);
setTimeout(() => {
tree.selectNode(this.domNode);
}, 0);
resolve();
});
});
}
unload(tree) {
this.children = [];
tree.aciTreeApi.unload(this.domNode);
return new Promise((resolve, reject)=>{
this.children = [];
tree.aciTreeApi.unload(this.domNode, {
success: ()=>{
resolve(true);
},
fail: ()=>{
reject();
},
});
});
}
open(tree, suppressNoDom) {
return new Promise((resolve, reject)=>{
if(suppressNoDom && (this.domNode == null || typeof(this.domNode) === 'undefined')) {
resolve(true);
} else if(tree.aciTreeApi.isOpen(this.domNode)) {
resolve(true);
} else {
tree.aciTreeApi.open(this.domNode, {
success: ()=>{
resolve(true);
},
fail: ()=>{
reject(true);
},
});
}
});
}
/*
@@ -202,6 +235,47 @@ export class Tree {
return findInTree(this.rootNode, path.join('.'));
}
findNodeWithToggle(path) {
let tree = this;
path = path.join('.');
let onCorrectPath = function(matchPath) {
return (matchPath !== undefined && path !== undefined
&& (path.startsWith(matchPath + '.') || path === matchPath));
};
return (function findInNode(currentNode) {
return new Promise((resolve, reject)=>{
if (path === null || path === undefined || path.length === 0) {
resolve(null);
}
/* No point in checking the children if
* the path for currentNode itself is not matching
*/
if (currentNode.path !== undefined && !onCorrectPath(currentNode.path)) {
reject(null);
} else if (currentNode.path === path) {
resolve(currentNode);
} else {
currentNode.open(tree, true)
.then(()=>{
for (let i = 0, length = currentNode.children.length; i < length; i++) {
let childNode = currentNode.children[i];
if(onCorrectPath(childNode.path)) {
resolve(findInNode(childNode));
return;
}
}
reject(null);
})
.catch(()=>{
reject(null);
});
}
});
})(this.rootNode);
}
findNodeByDomElement(domElement) {
const path = this.translateTreeNodeIdFromACITree(domElement);
if(!path || !path[0]) {
@@ -215,8 +289,19 @@ export class Tree {
return this.aciTreeApi.selected();
}
selectNode(aciTreeIdentifier) {
/* scrollIntoView will scroll only to top and bottom
* Logic can be added for scroll to middle
*/
scrollTo(domElement) {
domElement.scrollIntoView();
}
selectNode(aciTreeIdentifier, scrollOnSelect) {
this.aciTreeApi.select(aciTreeIdentifier);
if(scrollOnSelect) {
this.scrollTo(aciTreeIdentifier[0]);
}
}
createOrUpdateNode(id, data, parent, domNode) {
@@ -227,6 +312,7 @@ export class Tree {
const oldNode = this.findNode(oldNodePath);
if (oldNode !== null) {
oldNode.data = data;
oldNode.domNode = domNode;
return oldNode;
}
@@ -238,6 +324,18 @@ export class Tree {
return node;
}
unloadNode(id, data, domNode, parentPath) {
let oldNodePath = [id];
const parent = this.findNode(parentPath);
if(parent !== null && parent !== undefined) {
oldNodePath = [parent.path, id];
}
const oldNode = this.findNode(oldNodePath);
if(oldNode) {
oldNode.children = [];
}
}
/**
* Given the JQuery object that contains the ACI Tree
* this method is responsible for registering this tree class
@@ -252,16 +350,20 @@ export class Tree {
$treeJQuery.on('acitree', function (event, api, item, eventName) {
if (api.isItem(item)) {
/* If the id of node is changed, the path should also be changed */
if (eventName === 'added' || eventName === 'idset') {
if (['added', 'idset', 'beforeunload'].indexOf(eventName) != -1) {
const id = api.getId(item);
const data = api.itemData(item);
if(eventName === 'added') {
this.prepareDraggable(data, item);
}
const parentId = this.translateTreeNodeIdFromACITree(api.parent(item));
this.addNewNode(id, data, item, parentId);
if(eventName === 'beforeunload') {
this.unloadNode(id, data, item, parentId);
} else {
if(eventName === 'added') {
this.prepareDraggable(data, item);
}
this.addNewNode(id, data, item, parentId);
}
if(data.errmsg) {
Alertify.error(data.errmsg);
}

View File

@@ -32,11 +32,12 @@ export function findAndSetFocus(container) {
* browser. For eg, in safari focus() works only when element has
* tabindex="0", whereas in Chrome it works in any case
*/
if (first_el.length == 0) {
first_el = container
.find(`
.pgadmin-controls:first input:enabled,
.pgadmin-controls:first .btn:not(.toggle),
.pgadmin-controls:first,
.ajs-commands:first,
.CodeMirror-scroll`)
.find('*[tabindex]:not([tabindex="-1"])');

View File

@@ -119,21 +119,18 @@
}
.success-in-footer {
border-radius: 5px;
border: 1px solid transparent;
.alert-text {
border-color: $color-success-light;
}
border-radius: $border-radius;
border: 1px solid $color-success-light;
background: $color-success-light;
}
.info-in-footer {
border-radius: $border-radius;
border: 1px solid $color-primary;
border-radius: 4px;
height: 35px;
background: $color-primary-light;
.alert-text {
border: none;
.fa {
font-size: 1rem;
}
}
}

View File

@@ -166,7 +166,7 @@
.wcTabIcon {
background-position: center;
padding: 0px 10px;
padding: 0rem 0.75rem;
&.fa, &.pg-font-icon{
padding: 0rem 0.25rem 0rem 0rem

View File

@@ -0,0 +1,87 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""Implements Search Object feature"""
from flask import request
from flask_babelex import gettext
from flask_security import login_required
from pgadmin.utils import PgAdminModule
from pgadmin.utils.ajax import make_json_response, bad_request,\
internal_server_error
from pgadmin.utils.preferences import Preferences
from pgadmin.tools.search_objects.utils import SearchObjectsHelper
MODULE_NAME = 'search_objects'
class SearchObjectsModule(PgAdminModule):
LABEL = gettext('Search objects')
def get_exposed_url_endpoints(self):
"""
Returns:
list: URL endpoints for search_object module
"""
return ['search_objects.search', 'search_objects.types']
def show_system_objects(self):
"""
return system preference objects
"""
return self.pref_show_system_objects.get()
def register_preferences(self):
"""
Get show_system_objects preference
"""
browser_preference = Preferences.module('browser')
self.pref_show_system_objects =\
browser_preference.preference('show_system_objects')
# Create blueprint for BackupModule class
blueprint = SearchObjectsModule(
MODULE_NAME, __name__, static_url_path=''
)
@blueprint.route("/", endpoint='index')
@login_required
def index():
return bad_request(errormsg=_("This URL cannot be called directly."))
@blueprint.route("types/<int:sid>/<int:did>", endpoint='types')
@login_required
def types(sid, did):
so_obj = SearchObjectsHelper(sid, did, blueprint.show_system_objects())
return make_json_response(data=so_obj.get_supported_types())
@blueprint.route("search/<int:sid>/<int:did>", endpoint='search')
@login_required
def search(sid, did):
"""
URL args:
text <required>: search text
type <optional>: type of object to be searched.
"""
text = request.args.get('text', None)
obj_type = request.args.get('type', None)
so_obj = SearchObjectsHelper(sid, did, blueprint.show_system_objects())
status, res = so_obj.search(text, obj_type)
if not status:
return internal_server_error(errormsg=res)
return make_json_response(data=res)

View File

@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
define([
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'pgadmin.alertifyjs',
'sources/pgadmin', 'sources/csrf', 'pgadmin.browser.toolbar',
'pgadmin.search_objects/search_objects_dialog',
], function(
gettext, url_for, $, _, alertify, pgAdmin, csrfToken, toolBar, SearchObjectsDialog
) {
var pgBrowser = pgAdmin.Browser;
if (pgAdmin.SearchObjects)
return pgAdmin.SearchObjects;
pgAdmin.SearchObjects = {
init: function() {
if (this.initialized)
return;
this.initialized = true;
csrfToken.setPGCSRFToken(pgAdmin.csrf_token_header, pgAdmin.csrf_token);
// Define the nodes on which the menus to be appear
var menus = [{
name: 'search_objects',
module: this,
applies: ['tools'],
callback: 'show_search_objects',
enable: this.search_objects_enabled,
priority: 1,
label: gettext('Search objects'),
}, {
name: 'search_objects',
module: this,
applies: ['context'],
callback: 'show_search_objects',
enable: this.search_objects_enabled,
priority: 1,
label: gettext('Search objects'),
}];
pgBrowser.add_menus(menus);
return this;
},
search_objects_enabled: function(obj) {
/* Same as query tool */
var isEnabled = (() => {
if (!_.isUndefined(obj) && !_.isNull(obj)) {
if (_.indexOf(pgAdmin.unsupported_nodes, obj._type) == -1) {
if (obj._type == 'database' && obj.allowConn) {
return true;
} else if (obj._type != 'database') {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
})();
toolBar.enable(gettext('Search objects'), isEnabled);
return isEnabled;
},
// Callback to show the dialog
show_search_objects: function(action, item) {
let dialog = new SearchObjectsDialog.default(
pgBrowser,
$,
alertify,
{},
);
dialog.draw(action, item, {}, pgBrowser.stdW.md, pgBrowser.stdH.lg);
},
};
return pgAdmin.SearchObjects;
});

View File

@@ -0,0 +1,40 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import gettext from 'sources/gettext';
import {Dialog} from 'sources/alertify/dialog';
import {getPanelTitle} from 'tools/datagrid/static/js/datagrid_panel_title';
export default class SearchObjectsDialog extends Dialog {
constructor(pgBrowser, $, alertify, BackupModel, backform = null) {
super(gettext('Search Objects Error'),
'<div class=\'search_objects_dialog\'></div>',
pgBrowser, $, alertify, BackupModel, backform
);
}
dialogName() {
return 'search_objects';
}
draw(action, aciTreeItem, params, width=0, height=0) {
let dbInfo = this.retrieveAncestorOfTypeDatabase(aciTreeItem);
if (!dbInfo) {
return;
}
let dialogTitle = getPanelTitle(this.pgBrowser, aciTreeItem);
dialogTitle = gettext('Search Objects - ') + dialogTitle;
const dialog = this.createOrGetDialog(
gettext('Search Objects...'),
'search_objects'
);
dialog(dialogTitle).resizeTo(width, height);
}
}

View File

@@ -0,0 +1,649 @@
import {getTreeNodeHierarchyFromElement} from 'sources/tree/pgadmin_tree_node';
import axios from 'axios/index';
import gettext from 'sources/gettext';
import url_for from 'sources/url_for';
import 'select2';
import {DialogWrapper} from 'sources/alertify/dialog_wrapper';
import Slick from 'sources/../bundle/slickgrid';
import pgAdmin from 'sources/pgadmin';
export default class SearchObjectsDialogWrapper extends DialogWrapper {
constructor(dialogContainerSelector, dialogTitle, typeOfDialog,
jquery, pgBrowser, alertify, dialogModel, backform) {
super(dialogContainerSelector, dialogTitle, jquery,
pgBrowser, alertify, dialogModel, backform);
this.grid = null;
this.dataview = null;
this.gridContainer = null;
}
showMessage(text, is_error, call_after_show=()=>{}) {
if(text == '' || text == null) {
this.statusBar.classList.add('d-none');
} else {
if(is_error) {
this.statusBar.innerHTML = `
<div class="error-in-footer">
<div class="d-flex px-2 py-1">
<div class="pr-2">
<i class="fa fa-exclamation-triangle text-danger" aria-hidden="true" role="img"></i>
</div>
<div role="alert" class="alert-text">${text}</div>
<div class="ml-auto close-error-bar">
<a class="close-error fa fa-times text-danger"></a>
</div>
</div>
</div>
`;
this.statusBar.querySelector('.close-error').addEventListener('click', ()=>{
this.showMessage(null);
});
} else {
this.statusBar.innerHTML = `
<div class="info-in-footer">
<div class="d-flex px-2 py-1">
<div class="pr-2">
<i class="fa fa-info-circle text-primary" aria-hidden="true"></i>
</div>
<div class="alert-text" role="alert">${text}</div>
</div>
</div>
`;
}
this.statusBar.classList.remove('d-none');
call_after_show(this.statusBar);
}
}
createDialogDOM(dialogContainer) {
dialogContainer.innerHTML = `
<div class="d-flex flex-column w-100 h-100">
<div class="p-2">
<div class="row">
<div class="col-8 d-flex">
<div class="input-group pgadmin-controls">
<div class="input-group-prepend">
<span class="input-group-text fa fa-search" id="labelSearch" aria-label="` + gettext('Search') + `"></span>
</div>
<input type="search" class="form-control" id="txtGridSearch" placeholder="` + gettext('Type at least 3 characters') + `"
tabindex="0" aria-describedby="labelSearch" aria-labelledby="labelSearch" autocomplete="off">
</div>
<div class="ml-2">
<button class="btn btn-primary btn-search" disabled>`+ gettext('Search') +`</button>
</div>
</div>
<div class="col-4">
<select aria-label="` + gettext('Object types') + `" class="node-types"></select>
</div>
</div>
</div>
<div class="search-result-container flex-grow-1">
<div class="pg-sp-container d-none">
<div class="pg-sp-content">
<div class="row"><div class="col-12 pg-sp-icon"></div></div>
<div class="row"><div class="col-12 pg-sp-text"></div></div>
</div>
</div>
<div class="search-result"></div>
</div>
<div class='search-result-count p-1'>
</div>
<div class="pg-prop-status-bar">
</div>
</div>
`;
return dialogContainer;
}
updateDimOfSearchResult() {
let dim = this.searchResultContainer.getBoundingClientRect();
this.searchResult.style.height = dim.height + 'px';
this.searchResult.style.width = dim.width + 'px';
}
setLoading(text) {
if(text != null) {
this.loader.classList.remove('d-none');
this.loader.querySelector('.pg-sp-text').innerHTML = text;
} else {
this.loader.classList.add('d-none');
}
}
searchBtnEnabled(enabled) {
if(typeof(enabled) != 'undefined') {
this.searchBtn.disabled = !enabled;
} else {
return !this.searchBtn.disabled;
}
}
searchBoxVal(val) {
if(typeof(val) != 'undefined') {
this.searchBox.value = val;
} else {
return this.searchBox.value.trim();
}
}
typesVal(val) {
if(typeof(val) != 'undefined') {
this.typesSelect.value = val;
} else {
return this.typesSelect.value;
}
}
setTypes(data, enabled=true) {
this.jquery(this.typesSelect).empty().select2({
data: data,
});
this.typesSelect.disabled = !enabled;
}
setResultCount(count) {
if(count != 0 && !count) {
count = gettext('Unknown');
}
this.searchResultCount.innerHTML = count + ' ' +
(count===1 ? gettext('match found.'): gettext('matches found.'));
}
showOtherInfo(rowno) {
let rowData = this.dataview.getItem(rowno);
rowData.name += ` (${rowData.other_info})`;
rowData.other_info = null;
this.dataview.updateItem(rowData.id, rowData);
}
setGridData(data) {
this.dataview.setItems(data);
}
prepareGrid() {
this.dataview = new Slick.Data.DataView();
this.dataview.getItemMetadata = (row)=>{
let rowData = this.dataview.getItem(row);
if(!rowData.show_node){
return {
cssClasses: 'object-muted',
};
}
return null;
};
this.dataview.setFilter((item, args)=>{
return !(args && args.type != 'all' && item.type != args.type);
});
/* jquery required for select2 */
this.jquery(this.typesSelect).on('change', ()=>{
this.dataview.setFilterArgs({ type: this.typesVal() });
this.dataview.refresh();
});
this.dataview.onRowCountChanged.subscribe((e, args) => {
this.grid.updateRowCount();
this.grid.render();
this.setResultCount(args.current);
});
this.dataview.onRowsChanged.subscribe((e, args) => {
this.grid.invalidateRows(args.rows);
this.grid.render();
});
this.grid = new Slick.Grid(
this.searchResult,
this.dataview,
[
{ id: 'name', name: gettext('Object name'), field: 'name', sortable: true,
formatter: (row, cell, value, columnDef, dataContext) => {
let ret_el = `<i class='wcTabIcon ${dataContext.icon}'></i>${value}`;
if(dataContext.other_info != null && dataContext.other_info != '') {
ret_el += '&nbsp;<span class="object-other-info">(...)</span>';
}
return ret_el;
},
width: 50,
},
{ id: 'type', name: gettext('Type'), field: 'type_label', sortable: true, width: 35 },
{ id: 'path', name: gettext('Browser path'), field: 'path', sortable: false },
],
{
enableCellNavigation: true,
enableColumnReorder: false,
multiColumnSort: true,
explicitInitialization: true,
}
);
this.grid.registerPlugin(new Slick.AutoColumnSize());
this.grid.setSelectionModel(new Slick.RowSelectionModel({selectActiveRow: true}));
this.grid.onKeyDown.subscribe((event) => {
let activeRow = this.grid.getActiveCell();
if(activeRow && !event.ctrlKey && !event.altKey && !event.metaKey && event.keyCode == 9) {
event.preventDefault();
event.stopImmediatePropagation();
if(event.shiftKey) {
this.prevToGrid.focus();
} else {
this.nextToGrid.focus();
}
}
});
this.grid.onClick.subscribe((event, args) => {
if(event.target.classList.contains('object-other-info')) {
this.showOtherInfo(args.row);
}
});
this.grid.onDblClick.subscribe((event, args) => {
let rowData = this.dataview.getItem(args.row);
let treeMenu = this.pgBrowser.treeMenu;
if(!rowData.show_node) {
this.showMessage(
gettext('%s objects are disabled in the browser.', rowData.type_label) + ' ' +
gettext('You can enable them in the') + ' <a class="pref-dialog-link">' + gettext('preferences dialog') + '</a>.',
true,
(statusBar)=>{
statusBar.querySelector('.pref-dialog-link').addEventListener('click', ()=>{
if(pgAdmin.Preferences) {
pgAdmin.Preferences.show();
}
});
}
);
return false;
}
this.showMessage(gettext('Locating...'));
treeMenu.findNodeWithToggle(rowData.id_path)
.then((treeItem)=>{
treeMenu.selectNode(treeItem.domNode, true);
this.showMessage(null);
})
.catch((args)=>{
this.showMessage(gettext('Unable to locate this object in the browser.'), true);
console.warn(args);
});
});
this.grid.onSort.subscribe((event, args) => {
let cols = args.sortCols;
this.dataview.sort(function (dataRow1, dataRow2) {
for (var i = 0, l = cols.length; i < l; i++) {
var field = cols[i].sortCol.field;
var sign = cols[i].sortAsc ? 1 : -1;
var value1 = dataRow1[field], value2 = dataRow2[field];
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
if (result != 0) {
return result;
}
}
return false;
}, true);
});
}
onDialogResize() {
this.updateDimOfSearchResult();
if(this.grid) {
this.grid.resizeCanvas();
this.grid.autosizeColumns();
}
}
onDialogShow() {
this.focusOnDialog(this);
setTimeout(()=>{
if(!this.grid) {
this.prepareGrid();
}
this.updateDimOfSearchResult();
this.grid.init();
this.setGridData([]);
this.onDialogResize();
}, 500);
}
getBaseUrl(endpoint) {
return url_for('search_objects.'+endpoint, {
sid: this.treeInfo.server._id,
did: this.treeInfo.database._id,
});
}
getCollNode(node_type) {
if('coll-'+node_type in this.pgBrowser.Nodes) {
return this.pgBrowser.Nodes['coll-'+node_type];
} else if(node_type in this.pgBrowser.Nodes &&
typeof(this.pgBrowser.Nodes[node_type].collection_type) === 'string') {
return this.pgBrowser.Nodes[this.pgBrowser.Nodes[node_type].collection_type];
}
return null;
}
getSelectedNode() {
const tree = this.pgBrowser.treeMenu;
const selectedNode = tree.selected();
if (selectedNode) {
return tree.findNodeByDomElement(selectedNode);
} else {
return undefined;
}
}
finaliseData(datum) {
datum.icon = 'icon-' + datum.type;
/* finalise path */
[datum.path, datum.id_path] = this.translateSearchObjectsPath(datum.path, datum.catalog_level);
/* id is required by slickgrid dataview */
datum.id = datum.id_path;
return datum;
}
/* This function will translate the path given by search objects API into two parts
* 1. The display path on the UI
* 2. The tree search path to locate the object on the tree.
*
* Sample path returned by search objects API
* :schema.11:/pg_catalog/:table.2604:/pg_attrdef
*
* Sample path required by tree locator
* Normal object - server_group/1.server/3.coll-database/3.database/13258.coll-schema/13258.schema/2200.coll-table/2200.table/41773
* pg_catalog schema - server_group/1.server/3.coll-database/3.database/13258.coll-catalog/13258.catalog/11.coll-table/11.table/2600
* Information Schema, dbo, sys - server_group/1.server/3.coll-database/3.database/13258.coll-catalog/13258.catalog/12967.coll-catalog_object/12967.catalog_object/13204
*
* Column catalog_level has values as
* N - Not a catalog schema
* D - Catalog schema with DB support - pg_catalog
* O - Catalog schema with object support only - info schema, dbo, sys
*/
translateSearchObjectsPath(path, catalog_level) {
if (path === null) {
return path;
}
catalog_level = catalog_level || 'N';
/* path required by tree locator */
/* the path received from the backend is after the DB node, initial path setup */
let id_path = [
this.treeInfo.server_group.id,
this.treeInfo.server.id,
this.getCollNode('database').type + '/' + this.treeInfo.server._id,
this.treeInfo.database.id,
];
let prev_node_id = this.treeInfo.database._id;
/* add the slash to match regex, remove it from display path later */
path = '/' + path;
/* the below regex will match all /:server_group.1:/ */
let new_path = path.replace(/\/:[a-zA-Z_]+\.[0-9]+:\//g, (token)=>{
let orig_token = token;
/* remove the slash and colon */
token = token.slice(2, -2);
let [node_type, node_oid, others] = token.split('.');
if(typeof(others) !== 'undefined') {
return token;
}
/* schema type is "catalog" for catalog schemas */
node_type = (['D', 'O'].indexOf(catalog_level) != -1 && node_type == 'schema') ? 'catalog' : node_type;
/* catalog like info schema will only have views and tables AKA catalog_object except for pg_catalog */
node_type = (catalog_level === 'O' && ['view', 'table'].indexOf(node_type) != -1) ? 'catalog_object' : node_type;
/* If collection node present then add it */
let coll_node = this.getCollNode(node_type);
if(coll_node) {
/* Add coll node to the path */
if(prev_node_id != null) id_path.push(`${coll_node.type}/${prev_node_id}`);
/* Add the node to the path */
id_path.push(`${node_type}/${node_oid}`);
/* This will be needed for coll node */
prev_node_id = node_oid;
/* This will be displayed in the grid */
return `/${coll_node.label}/`;
} else if(node_type in this.pgBrowser.Nodes) {
/* Add the node to the path */
id_path.push(`${node_type}/${node_oid}`);
/* This will be need for coll node id path */
prev_node_id = node_oid;
/* Remove the token and replace with slash. This will be displayed in the grid */
return '/';
}
prev_node_id = null;
return orig_token;
});
/* Remove the slash we had added */
new_path = new_path.substring(1);
return [new_path, id_path];
}
prepareDialog() {
this.showMessage(null);
this.setResultCount(0);
if(this.grid) {
this.grid.destroy();
this.grid = null;
}
/* Load types */
this.setTypes([{
id: -1,
text: gettext('Loading...'),
value: null,
}], false);
axios.get(
this.getBaseUrl('types')
).then((res)=>{
let types = [{
id: 'all',
text: 'All types',
}];
for (const key of Object.keys(res.data.data).sort()) {
types.push({
id: key,
text: res.data.data[key],
});
}
this.setTypes(types);
}).catch(()=>{
this.setTypes([{
id: -1,
text: gettext('Failed'),
value: null,
}], false);
});
}
main(title) {
this.set('title', title);
}
setup() {
return {
buttons: [{
text: '',
key: 112,
className: 'btn btn-secondary pull-left fa fa-question pg-alertify-icon-button',
attrs: {
name: 'dialog_help',
type: 'button',
label: gettext('Help'),
'aria-label': gettext('Help'),
url: url_for('help.static', {
'filename': 'search_objects.html',
}),
},
}, {
text: gettext('Close'),
key: 27,
className: 'btn btn-secondary fa fa-lg fa-times pg-alertify-button',
'data-btn-name': 'cancel',
}],
// Set options for dialog
options: {
title: this.dialogTitle,
//disable both padding and overflow control.
padding: !1,
overflow: !1,
model: 0,
resizable: true,
maximizable: true,
pinnable: false,
closableByDimmer: false,
modal: false,
},
};
}
build() {
let tmpEle = document.createElement('div');
tmpEle.innerHTML = this.dialogContainerSelector;
let dialogContainer = tmpEle.firstChild;
// Append the container
this.elements.content.innerHTML = '';
this.elements.content.appendChild(dialogContainer);
this.createDialogDOM(dialogContainer);
this.alertify.pgDialogBuild.apply(this);
this.loader = dialogContainer.getElementsByClassName('pg-sp-container')[0];
this.searchBox = dialogContainer.querySelector('#txtGridSearch');
this.searchBtn = dialogContainer.querySelector('.btn-search');
this.typesSelect = dialogContainer.querySelector('.node-types');
this.searchResultContainer = dialogContainer.querySelector('.search-result-container');
this.searchResult = dialogContainer.querySelector('.search-result');
this.searchResultCount = dialogContainer.querySelector('.search-result-count');
this.statusBar = dialogContainer.querySelector('.pg-prop-status-bar');
/* These two values are required to come out of grid when tab is
* pressed in the grid. Slickgrid does not allow any way to come out
*/
this.nextToGrid = this.elements.footer.querySelector('.ajs-button');
this.prevToGrid = this.typesSelect;
/* init select2 */
this.setTypes([{
id: -1,
text: gettext('Loading...'),
value: null,
}], false);
/* on search box change */
this.searchBox.addEventListener('input', ()=>{
if(this.searchBoxVal().length >= 3) {
this.searchBtnEnabled(true);
} else {
this.searchBtnEnabled(false);
}
});
/* on enter key press */
this.searchBox.addEventListener('keypress', (e)=>{
if(e.keyCode == 13) {
e.stopPropagation();
if(this.searchBtnEnabled()) {
this.searchBtn.dispatchEvent(new Event('click'));
}
}
});
/* on search button click */
this.searchBtn.addEventListener('click', ()=>{
this.searchBtnEnabled(false);
this.setGridData([]);
this.showMessage(null);
this.setLoading(gettext('Searching....'));
axios.get(this.getBaseUrl('search'), {
params: {
text: this.searchBoxVal(),
type: this.typesVal(),
},
}).then((res)=>{
let grid_data = res.data.data.map((row)=>{
return this.finaliseData(row);
});
this.setGridData(grid_data);
}).catch((error)=>{
let errmsg = '';
if (error.response) {
errmsg = error.response.statusText;
} else if (error.request) {
errmsg = gettext('No response received');
} else {
errmsg = error.message;
}
this.showMessage(gettext('An unexpected occurred: %s', errmsg), true);
console.warn(error);
}).finally(()=>{
this.setLoading(null);
this.searchBtnEnabled(true);
});
});
this.set({
'onresized': this.onDialogResize.bind(this),
'onmaximized': this.onDialogResize.bind(this),
'onrestored': this.onDialogResize.bind(this),
'onshow': this.onDialogShow.bind(this),
});
}
prepare() {
let selectedTreeNode = this.getSelectedNode();
if (!this.getSelectedNodeData(selectedTreeNode)) {
return;
}
this.treeInfo = getTreeNodeHierarchyFromElement(this.pgBrowser, selectedTreeNode);
this.prepareDialog();
this.focusOnDialog(this);
}
callback(event) {
if (this.wasHelpButtonPressed(event)) {
event.cancel = true;
this.pgBrowser.showHelp(
event.button.element.name,
event.button.element.getAttribute('url'),
null,
null,
);
return;
}
}
}

View File

@@ -0,0 +1,122 @@
.search_objects_dialog {
height: 100%;
.object-other-info {
&:hover {
font-weight: bold;
}
}
.pref-dialog-link {
color: $color-fg !important;
text-decoration: underline !important;
cursor: pointer;
}
.search-result-container {
width: 100%;
height: 100%;
min-height: 0;
}
.node-types ~ .select2-container {
min-width: 100%;
}
.search-result-count {
border-top: $panel-border;
}
.ui-widget {
font-family: $font-family-primary;
font-size: $font-size-base;
.slick-header.ui-state-default {
border: $table-border-width solid $table-border-color;
.slick-header-columns {
background: $table-bg;
color: $color-fg;
border-bottom: $panel-border;
.slick-header-column-sorted {
font-style: unset;
}
.ui-state-default {
background: $table-bg !important;
color: $color-fg !important;
padding: $table-header-cell-padding $table-cell-padding;
border-right: $table-border-width solid $table-border-color;
.slick-column-name {
font-weight: bold;
}
.slick-sort-indicator {
float: unset;
}
}
.slick-header-sortable {
cursor: pointer !important;
.slick-sort-indicator-asc {
background: none;
border-top: none;
border-right: 0.25rem solid transparent;
border-bottom: 0.25rem solid $color-fg;
border-left: 0.25rem solid transparent;
}
.slick-sort-indicator-desc {
background: none;
border-top: 0.25rem solid $color-fg;
border-right: 0.25rem solid transparent;
border-bottom: none;
border-left: 0.25rem solid transparent;
}
}
}
}
.ui-widget-content {
color: $color-fg;
&.slick-row {
&.object-muted {
&.active, &.active:hover, &:hover, & {
.slick-cell {
color: $text-muted !important;
cursor: default !important;
}
}
}
&.active, &.active:hover {
.slick-cell {
border-top: $table-border-width solid transparent !important;
background-color: $tree-bg-selected !important;
color: $tree-fg-selected !important;
}
}
&:hover {
cursor: pointer;
.slick-cell {
border-top: $table-border-width solid transparent !important;
border-bottom: $table-border-width solid transparent !important;
background-color: $tree-bg-hover !important;
color: $tree-fg-hover !important;
cursor: pointer !important;
}
}
}
}
}
.pg-prop-status-bar {
position: absolute;
bottom: 0;
right: 0;
left: 0;
}
}

View File

@@ -0,0 +1,435 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
{% set all_obj = false %}
{% if obj_type == 'all' or obj_type is none %}
{% set all_obj = true %}
{% endif %}
SELECT obj_type, obj_name,
REPLACE(obj_path, '/'||sn.schema_name||'/', '/'||{{ CATALOGS.LABELS_SCHEMACOL('sn.schema_name', _) }}||'/') AS obj_path,
schema_name, show_node, other_info,
CASE
WHEN {{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }} THEN
CASE WHEN {{ CATALOGS.DB_SUPPORT_SCHEMACOL('sn.schema_name') }} THEN 'D' ELSE 'O' END
ELSE 'N'
END AS catalog_level
FROM (
{% if all_obj or obj_type in ['sequence', 'view', 'mview'] %}
SELECT
CASE
WHEN c.relkind = 'S' THEN 'sequence'
WHEN c.relkind = 'v' THEN 'view'
WHEN c.relkind = 'm' THEN 'mview'
ELSE 'should not happen'
END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN c.relkind = 'S' THEN ':sequence.'
WHEN c.relkind = 'v' THEN ':view.'
WHEN c.relkind = 'm' THEN ':mview.'
ELSE 'should not happen'
END || c.oid ||':/' || c.relname AS obj_path, n.nspname AS schema_name,
CASE
WHEN c.relkind = 'S' THEN {{ show_node_prefs['sequence'] }}
WHEN c.relkind = 'v' THEN {{ show_node_prefs['view'] }}
WHEN c.relkind = 'm' THEN {{ show_node_prefs['mview'] }}
ELSE False
END AS show_node, NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
{% if all_obj %}
WHERE c.relkind in ('S','v','m')
{% elif obj_type == 'sequence' %}
WHERE c.relkind = 'S'
{% elif obj_type == 'view' %}
WHERE c.relkind = 'v'
{% elif obj_type == 'mview' %}
WHERE c.relkind = 'm'
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['table', 'partition'] %}
SELECT CASE WHEN c.relispartition THEN 'partition' ELSE 'table' END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' || (
WITH RECURSIVE table_path_data as (
select c.oid as oid, 0 as height,
CASE c.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || c.oid || ':/' || c.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) obj_path, n.nspname AS schema_name,
CASE WHEN c.relispartition THEN {{ show_node_prefs['partition'] }}
ELSE {{ show_node_prefs['table'] }} END AS show_node,
NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind in ('p','r')
{% if obj_type == 'table' %}
AND NOT c.relispartition
{% elif obj_type == 'partition' %}
AND c.relispartition
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['index'] %}
SELECT 'index'::text AS obj_type, cls.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/:table.'|| tab.oid ||':/' || tab.relname || '/:index.'|| cls.oid ||':/' || cls.relname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
JOIN pg_namespace n ON n.oid=tab.relnamespace
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON des.objoid=cls.oid
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0)
WHERE contype IS NULL
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger_function', 'function'] %}
SELECT
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN 'trigger_function'
ELSE 'function' END::text AS obj_type, p.proname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' || case when t.typname = 'trigger' then ':trigger_function.' else ':function.' end || p.oid ||':/' || p.proname AS obj_path, n.nspname AS schema_name,
CASE WHEN t.typname IN ('trigger', 'event_trigger') THEN {{ show_node_prefs['trigger_function'] }} ELSE {{ show_node_prefs['function'] }} END AS show_node,
pg_catalog.pg_get_function_identity_arguments(p.oid) AS other_info
from pg_proc p
left join pg_namespace n on p.pronamespace = n.oid
left join pg_type t on p.prorettype = t.oid
WHERE ({{ CATALOGS.DB_SUPPORT('n') }})
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['event_trigger'] %}
select 'event_trigger'::text AS obj_type, evtname AS obj_name, ':event_trigger.'||oid||':/' || evtname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info from pg_event_trigger
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['schema'] %}
select 'schema'::text AS obj_type, n.nspname AS obj_name,
':schema.'||n.oid||':/' || n.nspname as obj_path, n.nspname AS schema_name,
{{ show_node_prefs['schema'] }} AS show_node, NULL AS other_info from pg_namespace n
where {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['column'] %}
select 'column'::text AS obj_type, a.attname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/' ||
case
WHEN t.relkind in ('r', 'p') THEN ':table.'
WHEN t.relkind = 'v' THEN ':view.'
WHEN t.relkind = 'm' THEN ':mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:column.'|| a.attnum ||':/' || a.attname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['column'] }} AS show_node, NULL AS other_info
from pg_attribute a
inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','p','v','m')
left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0
and not t.relispartition
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['constraints', 'check_constraint', 'foreign_key', 'primary_key', 'unique_constraint', 'exclusion_constraint'] %}
SELECT
CASE
WHEN c.contype = 'c' THEN 'check_constraint'
WHEN c.contype = 'f' THEN 'foreign_key'
WHEN c.contype = 'p' THEN 'primary_key'
WHEN c.contype = 'u' THEN 'unique_constraint'
WHEN c.contype = 'x' THEN 'exclusion_constraint'
END::text AS obj_type,
case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_name,
':schema.'||n.oid||':/' || n.nspname||'/'||
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) ||
CASE
WHEN c.contype = 'c' THEN '/:check_constraint.' ||c.oid
WHEN c.contype = 'f' THEN '/:foreign_key.' ||c.conindid
WHEN c.contype = 'p' THEN '/:primary_key.' ||c.conindid
WHEN c.contype = 'u' THEN '/:unique_constraint.' ||c.conindid
WHEN c.contype = 'x' THEN '/:exclusion_constraint.' ||c.conindid
END ||':/'|| case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['constraints'] }} AS show_node, NULL AS other_info
from pg_constraint c
left join pg_class t on c.conrelid = t.oid
left join pg_class tf on c.confrelid = tf.oid
left join pg_namespace n on t.relnamespace = n.oid
where c.contypid = 0
{% if obj_type == 'check_constraint' %}
AND c.contype = 'c'
{% elif obj_type == 'foreign_key' %}
AND c.contype = 'f'
{% elif obj_type == 'primary_key' %}
AND c.contype = 'p'
{% elif obj_type == 'unique_constraint' %}
AND c.contype = 'u'
{% elif obj_type == 'exclusion_constraint' %}
AND c.contype = 'x'
{% else %}
AND c.contype IN ('c', 'f', 'p', 'u', 'x')
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['rule'] %}
select 'rule'::text AS obj_type, r.rulename AS obj_name, ':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end
||'/:rule.'||r.oid||':/'|| r.rulename AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['rule'] }} AS show_node, NULL AS other_info
from pg_rewrite r
left join pg_class t on r.ev_class = t.oid
left join pg_namespace n on t.relnamespace = n.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger'] %}
select 'trigger'::text AS obj_type, tr.tgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end || '/:trigger.'|| tr.oid || ':/' || tr.tgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['trigger'] }} AS show_node, NULL AS other_info
from pg_trigger tr
left join pg_class t on tr.tgrelid = t.oid
left join pg_namespace n on t.relnamespace = n.oid
where tr.tgisinternal = false
and {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['type'] %}
SELECT 'type'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname ||
'/:type.'|| t.oid ||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['type'] }} AS show_node, NULL AS other_info
FROM pg_type t
LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_namespace n on t.typnamespace = n.oid
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%'
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['cast'] %}
SELECT 'cast'::text AS obj_type, format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_name,
':cast.'||ca.oid||':/' || format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['cast'] }} AS show_node, NULL AS other_info
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_type tt ON tt.oid=casttarget
{% if not show_system_objects %}
WHERE ca.oid > {{last_system_oid}}::OID
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['language'] %}
SELECT 'language'::text AS obj_type, lanname AS obj_name, ':language.'||lan.oid||':/' || lanname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['language'] }} AS show_node, NULL AS other_info
FROM pg_language lan
WHERE lanispl IS TRUE
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_configuration'] %}
SELECT 'fts_configuration'::text AS obj_type, cfg.cfgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:fts_configuration.'||cfg.oid||':/' || cfg.cfgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['fts_configuration'] }} AS show_node, NULL AS other_info
FROM pg_ts_config cfg
left join pg_namespace n on cfg.cfgnamespace = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_dictionary'] %}
SELECT 'fts_dictionary' AS obj_type, dict.dictname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_dictionary.'||dict.oid||':/' || dict.dictname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_dictionary'] }} AS show_node, NULL AS other_info
FROM pg_ts_dict dict
left join pg_namespace ns on dict.dictnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_parser'] %}
SELECT 'fts_parser' AS obj_type, prs.prsname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_parser.'||prs.oid||':/' || prs.prsname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_parser'] }} AS show_node, NULL AS other_info
FROM pg_ts_parser prs
left join pg_namespace ns on prs.prsnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_template'] %}
SELECT 'fts_template' AS obj_type, tmpl.tmplname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_template.'||tmpl.oid||':/' || tmpl.tmplname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_template'] }} AS show_node, NULL AS other_info
FROM pg_ts_template tmpl
left join pg_namespace ns on tmpl.tmplnamespace = ns.oid
AND {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain'] %}
select 'domain' AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['domain'] }} AS show_node, NULL AS other_info
from pg_type t
inner join pg_namespace n on t.typnamespace = n.oid
where t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain_constraints'] %}
SELECT 'domain_constraints' AS obj_type,
c.conname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname || '/:domain_constraints.'||c.oid||':/' || c.conname AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['domain_constraints'] }} AS show_node, NULL AS other_info
FROM pg_constraint c JOIN pg_type t
ON t.oid=contypid JOIN pg_namespace n
ON n.oid=t.typnamespace
WHERE t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_data_wrapper'] %}
select 'foreign_data_wrapper' AS obj_type, fdwname AS obj_name, ':foreign_data_wrapper.'||oid||':/' || fdwname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_data_wrapper'] }} AS show_node, NULL AS other_info
from pg_foreign_data_wrapper
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_server'] %}
select 'foreign_server' AS obj_type, sr.srvname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_server'] }} AS show_node, NULL AS other_info
from pg_foreign_server sr
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['user_mapping'] %}
select 'user_mapping' AS obj_type, ro.rolname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname || '/:user_mapping.'||ro.oid||':/' || ro.rolname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['user_mapping'] }} AS show_node, NULL AS other_info
from pg_user_mapping um
inner join pg_roles ro on um.umuser = ro.oid
inner join pg_foreign_server sr on um.umserver = sr.oid
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_table'] %}
select 'foreign_table' AS obj_type, c.relname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:foreign_table.'||c.oid||':/' || c.relname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['foreign_table'] }} AS show_node, NULL AS other_info
from pg_foreign_table ft
inner join pg_class c on ft.ftrelid = c.oid
inner join pg_namespace ns on c.relnamespace = ns.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['extension'] %}
select 'extension' AS obj_type, x.extname AS obj_name, ':extension.'||x.oid||':/' || x.extname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['extension'] }} AS show_node, NULL AS other_info
FROM pg_extension x
JOIN pg_namespace n on x.extnamespace=n.oid
join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['collation'] %}
SELECT 'collation' AS obj_type, c.collname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:collation.'||c.oid||':/' || c.collname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['collation'] }} AS show_node, NULL AS other_info
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
{% if not show_system_objects %}
AND NOT ({{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }})
AND (sn.schema_name IS NOT NULL AND sn.schema_name NOT LIKE 'pg\_%')
{% endif %}
ORDER BY 1, 2, 3

View File

@@ -0,0 +1,452 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
{% set all_obj = false %}
{% if obj_type == 'all' or obj_type is none %}
{% set all_obj = true %}
{% endif %}
SELECT obj_type, obj_name,
REPLACE(obj_path, '/'||sn.schema_name||'/', '/'||{{ CATALOGS.LABELS_SCHEMACOL('sn.schema_name', _) }}||'/') AS obj_path,
schema_name, show_node, other_info,
CASE
WHEN {{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }} THEN
CASE WHEN {{ CATALOGS.DB_SUPPORT_SCHEMACOL('sn.schema_name') }} THEN 'D' ELSE 'O' END
ELSE 'N'
END AS catalog_level
FROM (
{% if all_obj or obj_type in ['sequence', 'view', 'mview'] %}
SELECT
CASE
WHEN c.relkind = 'S' THEN 'sequence'
WHEN c.relkind = 'v' THEN 'view'
WHEN c.relkind = 'm' THEN 'mview'
ELSE 'should not happen'
END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN c.relkind = 'S' THEN ':sequence.'
WHEN c.relkind = 'v' THEN ':view.'
WHEN c.relkind = 'm' THEN ':mview.'
ELSE 'should not happen'
END || c.oid ||':/' || c.relname AS obj_path, n.nspname AS schema_name,
CASE
WHEN c.relkind = 'S' THEN {{ show_node_prefs['sequence'] }}
WHEN c.relkind = 'v' THEN {{ show_node_prefs['view'] }}
WHEN c.relkind = 'm' THEN {{ show_node_prefs['mview'] }}
ELSE False
END AS show_node, NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
{% if all_obj %}
WHERE c.relkind in ('S','v','m')
{% elif obj_type == 'sequence' %}
WHERE c.relkind = 'S'
{% elif obj_type == 'view' %}
WHERE c.relkind = 'v'
{% elif obj_type == 'mview' %}
WHERE c.relkind = 'm'
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['table', 'partition'] %}
SELECT CASE WHEN c.relispartition THEN 'partition' ELSE 'table' END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' || (
WITH RECURSIVE table_path_data as (
select c.oid as oid, 0 as height,
CASE c.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || c.oid || ':/' || c.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) obj_path, n.nspname AS schema_name,
CASE WHEN c.relispartition THEN {{ show_node_prefs['partition'] }}
ELSE {{ show_node_prefs['table'] }} END AS show_node,
NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind in ('p','r')
{% if obj_type == 'table' %}
AND NOT c.relispartition
{% elif obj_type == 'partition' %}
AND c.relispartition
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['index'] %}
SELECT 'index'::text AS obj_type, cls.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/:table.'|| tab.oid ||':/' || tab.relname || '/:index.'|| cls.oid ||':/' || cls.relname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
JOIN pg_namespace n ON n.oid=tab.relnamespace
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON des.objoid=cls.oid
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0)
WHERE contype IS NULL
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger_function', 'function', 'procedure'] %}
SELECT
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN 'trigger_function'
WHEN p.prokind = 'p' THEN 'procedure'
ELSE 'function'
END::text AS obj_type, p.proname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN ':trigger_function.'
WHEN p.prokind = 'p' THEN ':procedure.'
ELSE ':function.'
END || p.oid ||':/' || p.proname AS obj_path, n.nspname AS schema_name,
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN {{ show_node_prefs['trigger_function'] }}
WHEN p.prokind = 'p' THEN {{ show_node_prefs['procedure'] }}
ELSE {{ show_node_prefs['function'] }}
END AS show_node,
pg_catalog.pg_get_function_identity_arguments(p.oid) AS other_info
from pg_proc p join pg_namespace n
on p.pronamespace = n.oid join pg_type t
on p.prorettype = t.oid join pg_language lng
ON lng.oid=p.prolang
WHERE p.prokind IN ('f', 'w', 'p')
AND CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN lng.lanname NOT IN ('edbspl', 'sql', 'internal')
ELSE true
END
AND ({{ CATALOGS.DB_SUPPORT('n') }})
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['event_trigger'] %}
select 'event_trigger'::text AS obj_type, evtname AS obj_name, ':event_trigger.'||oid||':/' || evtname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info from pg_event_trigger
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['schema'] %}
select 'schema'::text AS obj_type, n.nspname AS obj_name,
':schema.'||n.oid||':/' || n.nspname as obj_path, n.nspname AS schema_name,
{{ show_node_prefs['schema'] }} AS show_node, NULL AS other_info from pg_namespace n
where {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['column'] %}
select 'column'::text AS obj_type, a.attname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/' ||
case
WHEN t.relkind in ('r', 'p') THEN ':table.'
WHEN t.relkind = 'v' THEN ':view.'
WHEN t.relkind = 'm' THEN ':mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:column.'|| a.attnum ||':/' || a.attname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['column'] }} AS show_node, NULL AS other_info
from pg_attribute a
inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','p','v','m')
left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0
and not t.relispartition
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['constraints', 'check_constraint', 'foreign_key', 'primary_key', 'unique_constraint', 'exclusion_constraint'] %}
SELECT
CASE
WHEN c.contype = 'c' THEN 'check_constraint'
WHEN c.contype = 'f' THEN 'foreign_key'
WHEN c.contype = 'p' THEN 'primary_key'
WHEN c.contype = 'u' THEN 'unique_constraint'
WHEN c.contype = 'x' THEN 'exclusion_constraint'
END::text AS obj_type,
case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_name,
':schema.'||n.oid||':/' || n.nspname||'/'||
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) ||
CASE
WHEN c.contype = 'c' THEN '/:check_constraint.' ||c.oid
WHEN c.contype = 'f' THEN '/:foreign_key.' ||c.conindid
WHEN c.contype = 'p' THEN '/:primary_key.' ||c.conindid
WHEN c.contype = 'u' THEN '/:unique_constraint.' ||c.conindid
WHEN c.contype = 'x' THEN '/:exclusion_constraint.' ||c.conindid
END ||':/'|| case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['constraints'] }} AS show_node, NULL AS other_info
from pg_constraint c
left join pg_class t on c.conrelid = t.oid
left join pg_class tf on c.confrelid = tf.oid
left join pg_namespace n on t.relnamespace = n.oid
where c.contypid = 0
{% if obj_type == 'check_constraint' %}
AND c.contype = 'c'
{% elif obj_type == 'foreign_key' %}
AND c.contype = 'f'
{% elif obj_type == 'primary_key' %}
AND c.contype = 'p'
{% elif obj_type == 'unique_constraint' %}
AND c.contype = 'u'
{% elif obj_type == 'exclusion_constraint' %}
AND c.contype = 'x'
{% else %}
AND c.contype IN ('c', 'f', 'p', 'u', 'x')
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['rule'] %}
select 'rule'::text AS obj_type, r.rulename AS obj_name, ':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end
||'/:rule.'||r.oid||':/'|| r.rulename AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['rule'] }} AS show_node, NULL AS other_info
from pg_rewrite r
left join pg_class t on r.ev_class = t.oid
left join pg_namespace n on t.relnamespace = n.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger'] %}
select 'trigger'::text AS obj_type, tr.tgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end || '/:trigger.'|| tr.oid || ':/' || tr.tgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['trigger'] }} AS show_node, NULL AS other_info
from pg_trigger tr
left join pg_class t on tr.tgrelid = t.oid
left join pg_namespace n on t.relnamespace = n.oid
where tr.tgisinternal = false
and {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['type'] %}
SELECT 'type'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname ||
'/:type.'|| t.oid ||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['type'] }} AS show_node, NULL AS other_info
FROM pg_type t
LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_namespace n on t.typnamespace = n.oid
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%'
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['cast'] %}
SELECT 'cast'::text AS obj_type, format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_name,
':cast.'||ca.oid||':/' || format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['cast'] }} AS show_node, NULL AS other_info
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_type tt ON tt.oid=casttarget
{% if not show_system_objects %}
WHERE ca.oid > {{last_system_oid}}::OID
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['language'] %}
SELECT 'language'::text AS obj_type, lanname AS obj_name, ':language.'||lan.oid||':/' || lanname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['language'] }} AS show_node, NULL AS other_info
FROM pg_language lan
WHERE lanispl IS TRUE
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_configuration'] %}
SELECT 'fts_configuration'::text AS obj_type, cfg.cfgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:fts_configuration.'||cfg.oid||':/' || cfg.cfgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['fts_configuration'] }} AS show_node, NULL AS other_info
FROM pg_ts_config cfg
left join pg_namespace n on cfg.cfgnamespace = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_dictionary'] %}
SELECT 'fts_dictionary' AS obj_type, dict.dictname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_dictionary.'||dict.oid||':/' || dict.dictname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_dictionary'] }} AS show_node, NULL AS other_info
FROM pg_ts_dict dict
left join pg_namespace ns on dict.dictnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_parser'] %}
SELECT 'fts_parser' AS obj_type, prs.prsname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_parser.'||prs.oid||':/' || prs.prsname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_parser'] }} AS show_node, NULL AS other_info
FROM pg_ts_parser prs
left join pg_namespace ns on prs.prsnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_template'] %}
SELECT 'fts_template' AS obj_type, tmpl.tmplname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_template.'||tmpl.oid||':/' || tmpl.tmplname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_template'] }} AS show_node, NULL AS other_info
FROM pg_ts_template tmpl
left join pg_namespace ns on tmpl.tmplnamespace = ns.oid
AND {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain'] %}
select 'domain' AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['domain'] }} AS show_node, NULL AS other_info
from pg_type t
inner join pg_namespace n on t.typnamespace = n.oid
where t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain_constraints'] %}
SELECT 'domain_constraints' AS obj_type,
c.conname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname || '/:domain_constraints.'||c.oid||':/' || c.conname AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['domain_constraints'] }} AS show_node, NULL AS other_info
FROM pg_constraint c JOIN pg_type t
ON t.oid=contypid JOIN pg_namespace n
ON n.oid=t.typnamespace
WHERE t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_data_wrapper'] %}
select 'foreign_data_wrapper' AS obj_type, fdwname AS obj_name, ':foreign_data_wrapper.'||oid||':/' || fdwname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_data_wrapper'] }} AS show_node, NULL AS other_info
from pg_foreign_data_wrapper
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_server'] %}
select 'foreign_server' AS obj_type, sr.srvname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_server'] }} AS show_node, NULL AS other_info
from pg_foreign_server sr
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['user_mapping'] %}
select 'user_mapping' AS obj_type, ro.rolname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname || '/:user_mapping.'||ro.oid||':/' || ro.rolname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['user_mapping'] }} AS show_node, NULL AS other_info
from pg_user_mapping um
inner join pg_roles ro on um.umuser = ro.oid
inner join pg_foreign_server sr on um.umserver = sr.oid
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_table'] %}
select 'foreign_table' AS obj_type, c.relname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:foreign_table.'||c.oid||':/' || c.relname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['foreign_table'] }} AS show_node, NULL AS other_info
from pg_foreign_table ft
inner join pg_class c on ft.ftrelid = c.oid
inner join pg_namespace ns on c.relnamespace = ns.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['extension'] %}
select 'extension' AS obj_type, x.extname AS obj_name, ':extension.'||x.oid||':/' || x.extname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['extension'] }} AS show_node, NULL AS other_info
FROM pg_extension x
JOIN pg_namespace n on x.extnamespace=n.oid
join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['collation'] %}
SELECT 'collation' AS obj_type, c.collname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:collation.'||c.oid||':/' || c.collname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['collation'] }} AS show_node, NULL AS other_info
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
{% if not show_system_objects %}
AND NOT ({{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }})
AND (sn.schema_name IS NOT NULL AND sn.schema_name NOT LIKE 'pg\_%')
{% endif %}
ORDER BY 1, 2, 3

View File

@@ -0,0 +1,367 @@
{% import 'catalog/pg/macros/catalogs.sql' as CATALOGS %}
{% set all_obj = false %}
{% if obj_type == 'all' or obj_type is none %}
{% set all_obj = true %}
{% endif %}
SELECT obj_type, obj_name,
REPLACE(obj_path, '/'||sn.schema_name||'/', '/'||{{ CATALOGS.LABELS_SCHEMACOL('sn.schema_name', _) }}||'/') AS obj_path,
schema_name, show_node, other_info,
CASE
WHEN {{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }} THEN
CASE WHEN {{ CATALOGS.DB_SUPPORT_SCHEMACOL('sn.schema_name') }} THEN 'D' ELSE 'O' END
ELSE 'N'
END AS catalog_level
FROM (
{% if all_obj or obj_type in ['table', 'sequence', 'view', 'mview'] %}
SELECT
CASE
WHEN c.relkind = 'r' THEN 'table'
WHEN c.relkind = 'S' THEN 'sequence'
WHEN c.relkind = 'v' THEN 'view'
WHEN c.relkind = 'm' THEN 'mview'
ELSE 'should not happen'
END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN c.relkind = 'r' THEN ':table.'
WHEN c.relkind = 'S' THEN ':sequence.'
WHEN c.relkind = 'v' THEN ':view.'
WHEN c.relkind = 'm' THEN ':mview.'
ELSE 'should not happen'
END || c.oid ||':/' || c.relname AS obj_path, n.nspname AS schema_name,
CASE
WHEN c.relkind = 'r' THEN {{ show_node_prefs['table'] }}
WHEN c.relkind = 'S' THEN {{ show_node_prefs['sequence'] }}
WHEN c.relkind = 'v' THEN {{ show_node_prefs['view'] }}
WHEN c.relkind = 'm' THEN {{ show_node_prefs['mview'] }}
ELSE False
END AS show_node, NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
{% if all_obj %}
WHERE c.relkind in ('r','S','v','m')
{% elif obj_type == 'table' %}
WHERE c.relkind = 'r'
{% elif obj_type == 'sequence' %}
WHERE c.relkind = 'S'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% elif obj_type == 'view' %}
WHERE c.relkind = 'v'
{% elif obj_type == 'mview' %}
WHERE c.relkind = 'm'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['index'] %}
SELECT 'index'::text AS obj_type, cls.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/:table.'|| tab.oid ||':/' || tab.relname || '/:index.'|| cls.oid ||':/' || cls.relname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
JOIN pg_namespace n ON n.oid=tab.relnamespace
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON des.objoid=cls.oid
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0)
WHERE contype IS NULL
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger_function', 'function'] %}
SELECT
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN 'trigger_function'
ELSE 'function' END::text AS obj_type, p.proname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' || case when t.typname = 'trigger' then ':trigger_function.' else ':function.' end || p.oid ||':/' || p.proname AS obj_path, n.nspname AS schema_name,
CASE WHEN t.typname IN ('trigger', 'event_trigger') THEN {{ show_node_prefs['trigger_function'] }} ELSE {{ show_node_prefs['function'] }} END AS show_node,
pg_catalog.pg_get_function_identity_arguments(p.oid) AS other_info
from pg_proc p
left join pg_namespace n on p.pronamespace = n.oid
left join pg_type t on p.prorettype = t.oid
WHERE ({{ CATALOGS.DB_SUPPORT('n') }})
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['event_trigger'] %}
select 'event_trigger'::text AS obj_type, evtname AS obj_name, ':event_trigger.'||oid||':/' || evtname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info from pg_event_trigger
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['schema'] %}
select 'schema'::text AS obj_type, n.nspname AS obj_name,
':schema.'||n.oid||':/' || n.nspname as obj_path, n.nspname AS schema_name,
{{ show_node_prefs['schema'] }} AS show_node, NULL AS other_info from pg_namespace n
where {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['column'] %}
select 'column'::text AS obj_type, a.attname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/' ||
case
WHEN t.relkind = 'r' THEN ':table.'
WHEN t.relkind = 'v' THEN ':view.'
WHEN t.relkind = 'm' THEN ':mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:column.'|| a.attnum ||':/' || a.attname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['column'] }} AS show_node, NULL AS other_info
from pg_attribute a
inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','v','m')
left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['constraints', 'check_constraint', 'foreign_key', 'primary_key', 'unique_constraint', 'exclusion_constraint'] %}
SELECT
CASE
WHEN c.contype = 'c' THEN 'check_constraint'
WHEN c.contype = 'f' THEN 'foreign_key'
WHEN c.contype = 'p' THEN 'primary_key'
WHEN c.contype = 'u' THEN 'unique_constraint'
WHEN c.contype = 'x' THEN 'exclusion_constraint'
END::text AS obj_type,
case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_name,
':schema.'||n.oid||':/' || n.nspname||'/:table.'|| t.oid || ':/'||t.relname||
CASE
WHEN c.contype = 'c' THEN '/:check_constraint.' ||c.oid
WHEN c.contype = 'f' THEN '/:foreign_key.' ||c.conindid
WHEN c.contype = 'p' THEN '/:primary_key.' ||c.conindid
WHEN c.contype = 'u' THEN '/:unique_constraint.' ||c.conindid
WHEN c.contype = 'x' THEN '/:exclusion_constraint.' ||c.conindid
END ||':/'|| case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['constraints'] }} AS show_node, NULL AS other_info
from pg_constraint c
left join pg_class t on c.conrelid = t.oid
left join pg_class tf on c.confrelid = tf.oid
left join pg_namespace n on t.relnamespace = n.oid
where c.contypid = 0
{% if obj_type == 'check_constraint' %}
AND c.contype = 'c'
{% elif obj_type == 'foreign_key' %}
AND c.contype = 'f'
{% elif obj_type == 'primary_key' %}
AND c.contype = 'p'
{% elif obj_type == 'unique_constraint' %}
AND c.contype = 'u'
{% elif obj_type == 'exclusion_constraint' %}
AND c.contype = 'x'
{% else %}
AND c.contype IN ('c', 'f', 'p', 'u', 'x')
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['rule'] %}
select 'rule'::text AS obj_type, r.rulename AS obj_name, ':schema.'||n.oid||':/' || n.nspname||
case
WHEN t.relkind = 'r' THEN '/:table.'
when t.relkind = 'v' then '/:view.'
when t.relkind = 'm' then '/:mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname ||'/:rule.'||r.oid||':/'|| r.rulename AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['rule'] }} AS show_node, NULL AS other_info
from pg_rewrite r
left join pg_class t on r.ev_class = t.oid
left join pg_namespace n on t.relnamespace = n.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger'] %}
select 'trigger'::text AS obj_type, tr.tgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname||
case
WHEN t.relkind = 'r' THEN '/:table.'
when t.relkind = 'v' then '/:view.'
when t.relkind = 'm' then '/:mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:trigger.'|| tr.oid || ':/' || tr.tgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['trigger'] }} AS show_node, NULL AS other_info
from pg_trigger tr
left join pg_class t on tr.tgrelid = t.oid
left join pg_namespace n on t.relnamespace = n.oid
where tr.tgisinternal = false
and {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['type'] %}
SELECT 'type'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname ||
'/:type.'|| t.oid ||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['type'] }} AS show_node, NULL AS other_info
FROM pg_type t
LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_namespace n on t.typnamespace = n.oid
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%'
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['cast'] %}
SELECT 'cast'::text AS obj_type, format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_name,
':cast.'||ca.oid||':/' || format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['cast'] }} AS show_node, NULL AS other_info
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_type tt ON tt.oid=casttarget
{% if not show_system_objects %}
WHERE ca.oid > {{last_system_oid}}::OID
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['language'] %}
SELECT 'language'::text AS obj_type, lanname AS obj_name, ':language.'||lan.oid||':/' || lanname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['language'] }} AS show_node, NULL AS other_info
FROM pg_language lan
WHERE lanispl IS TRUE
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_configuration'] %}
SELECT 'fts_configuration'::text AS obj_type, cfg.cfgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:fts_configuration.'||cfg.oid||':/' || cfg.cfgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['fts_configuration'] }} AS show_node, NULL AS other_info
FROM pg_ts_config cfg
left join pg_namespace n on cfg.cfgnamespace = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_dictionary'] %}
SELECT 'fts_dictionary'::text AS obj_type, dict.dictname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_dictionary.'||dict.oid||':/' || dict.dictname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_dictionary'] }} AS show_node, NULL AS other_info
FROM pg_ts_dict dict
left join pg_namespace ns on dict.dictnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_parser'] %}
SELECT 'fts_parser'::text AS obj_type, prs.prsname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_parser.'||prs.oid||':/' || prs.prsname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_parser'] }} AS show_node, NULL AS other_info
FROM pg_ts_parser prs
left join pg_namespace ns on prs.prsnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_template'] %}
SELECT 'fts_template'::text AS obj_type, tmpl.tmplname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_template.'||tmpl.oid||':/' || tmpl.tmplname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_template'] }} AS show_node, NULL AS other_info
FROM pg_ts_template tmpl
left join pg_namespace ns on tmpl.tmplnamespace = ns.oid
AND {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain'] %}
select 'domain'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['domain'] }} AS show_node, NULL AS other_info
from pg_type t
inner join pg_namespace n on t.typnamespace = n.oid
where t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain_constraints'] %}
SELECT 'domain_constraints'::text AS obj_type,
c.conname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname || '/:domain_constraints.'||c.oid||':/' || c.conname AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['domain_constraints'] }} AS show_node, NULL AS other_info
FROM pg_constraint c JOIN pg_type t
ON t.oid=contypid JOIN pg_namespace n
ON n.oid=t.typnamespace
WHERE t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_data_wrapper'] %}
select 'foreign_data_wrapper'::text AS obj_type, fdwname AS obj_name, ':foreign_data_wrapper.'||oid||':/' || fdwname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_data_wrapper'] }} AS show_node, NULL AS other_info
from pg_foreign_data_wrapper
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_server'] %}
select 'foreign_server'::text AS obj_type, sr.srvname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_server'] }} AS show_node, NULL AS other_info
from pg_foreign_server sr
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['user_mapping'] %}
select 'user_mapping'::text AS obj_type, ro.rolname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname || '/:user_mapping.'||ro.oid||':/' || ro.rolname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['user_mapping'] }} AS show_node, NULL AS other_info
from pg_user_mapping um
inner join pg_roles ro on um.umuser = ro.oid
inner join pg_foreign_server sr on um.umserver = sr.oid
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_table'] %}
select 'foreign_table'::text AS obj_type, c.relname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:foreign_table.'||c.oid||':/' || c.relname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['foreign_table'] }} AS show_node, NULL AS other_info
from pg_foreign_table ft
inner join pg_class c on ft.ftrelid = c.oid
inner join pg_namespace ns on c.relnamespace = ns.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['extension'] %}
select 'extension'::text AS obj_type, x.extname AS obj_name, ':extension.'||x.oid||':/' || x.extname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['extension'] }} AS show_node, NULL AS other_info
FROM pg_extension x
JOIN pg_namespace n on x.extnamespace=n.oid
join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['collation'] %}
SELECT 'collation'::text AS obj_type, c.collname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:collation.'||c.oid||':/' || c.collname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['collation'] }} AS show_node, NULL AS other_info
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
{% if not show_system_objects %}
AND NOT ({{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }})
AND (sn.schema_name IS NOT NULL AND sn.schema_name NOT LIKE 'pg\_%')
{% endif %}
ORDER BY 1, 2, 3

View File

@@ -0,0 +1,493 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
{% set all_obj = false %}
{% if obj_type == 'all' or obj_type is none %}
{% set all_obj = true %}
{% endif %}
SELECT obj_type, obj_name,
REPLACE(obj_path, '/'||sn.schema_name||'/', '/'||{{ CATALOGS.LABELS_SCHEMACOL('sn.schema_name', _) }}||'/') AS obj_path,
schema_name, show_node, other_info,
CASE
WHEN {{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }} THEN
CASE WHEN {{ CATALOGS.DB_SUPPORT_SCHEMACOL('sn.schema_name') }} THEN 'D' ELSE 'O' END
ELSE 'N'
END AS catalog_level
FROM (
{% if all_obj or obj_type in ['sequence', 'view', 'mview'] %}
SELECT
CASE
WHEN c.relkind = 'S' THEN 'sequence'
WHEN c.relkind = 'v' THEN 'view'
WHEN c.relkind = 'm' THEN 'mview'
ELSE 'should not happen'
END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN c.relkind = 'S' THEN ':sequence.'
WHEN c.relkind = 'v' THEN ':view.'
WHEN c.relkind = 'm' THEN ':mview.'
ELSE 'should not happen'
END || c.oid ||':/' || c.relname AS obj_path, n.nspname AS schema_name,
CASE
WHEN c.relkind = 'S' THEN {{ show_node_prefs['sequence'] }}
WHEN c.relkind = 'v' THEN {{ show_node_prefs['view'] }}
WHEN c.relkind = 'm' THEN {{ show_node_prefs['mview'] }}
ELSE False
END AS show_node, NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
{% if all_obj %}
WHERE c.relkind in ('S','v','m')
{% elif obj_type == 'sequence' %}
WHERE c.relkind = 'S'
{% elif obj_type == 'view' %}
WHERE c.relkind = 'v'
{% elif obj_type == 'mview' %}
WHERE c.relkind = 'm'
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['table', 'partition'] %}
SELECT CASE WHEN c.relispartition THEN 'partition' ELSE 'table' END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' || (
WITH RECURSIVE table_path_data as (
select c.oid as oid, 0 as height,
CASE c.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || c.oid || ':/' || c.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) obj_path, n.nspname AS schema_name,
CASE WHEN c.relispartition THEN {{ show_node_prefs['partition'] }}
ELSE {{ show_node_prefs['table'] }} END AS show_node,
NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind in ('p','r')
{% if obj_type == 'table' %}
AND NOT c.relispartition
{% elif obj_type == 'partition' %}
AND c.relispartition
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['index'] %}
SELECT 'index'::text AS obj_type, cls.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/:table.'|| tab.oid ||':/' || tab.relname || '/:index.'|| cls.oid ||':/' || cls.relname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
JOIN pg_namespace n ON n.oid=tab.relnamespace
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON des.objoid=cls.oid
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0)
WHERE contype IS NULL
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger_function', 'function', 'procedure', 'edbfunc', 'edbproc'] %}
SELECT fd.obj_type, fd.obj_name,
CASE
WHEN fd.obj_type = 'function' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:function.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'procedure' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:procedure.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'trigger_function' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:trigger_function.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'edbfunc' THEN
':schema.'|| fd.next_schema_oid || ':/' || fd.next_schema_name || '/:package.'|| fd.schema_oid || ':/' || fd.schema_name || '/:edbfunc.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'edbproc' THEN
':schema.'|| fd.next_schema_oid || ':/' || fd.next_schema_name || '/:package.'|| fd.schema_oid || ':/' || fd.schema_name || '/:edbproc.' || fd.obj_oid ||':/' || fd.obj_name
ELSE NULL
END AS obj_path,
CASE
WHEN fd.obj_type IN ('function', 'procedure', 'trigger_function') THEN fd.schema_name
WHEN fd.obj_type IN ('edbfunc', 'edbproc') THEN fd.next_schema_name
ELSE NULL
END AS schema_name,
CASE
WHEN fd.obj_type = 'function' THEN {{ show_node_prefs['function'] }}
WHEN fd.obj_type = 'procedure' THEN {{ show_node_prefs['procedure'] }}
WHEN fd.obj_type = 'trigger_function' THEN {{ show_node_prefs['trigger_function'] }}
WHEN fd.obj_type = 'edbfunc' THEN {{ show_node_prefs['edbfunc'] }}
WHEN fd.obj_type = 'edbproc' THEN {{ show_node_prefs['edbproc'] }}
ELSE NULL
END AS show_node, other_info
FROM (
SELECT
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN 'trigger_function'
WHEN pr.protype = '0'::char THEN
CASE WHEN np.oid IS NOT NULL THEN 'edbfunc' ELSE 'function' END
WHEN pr.protype = '1'::char THEN
CASE WHEN np.oid IS NOT NULL THEN 'edbproc' ELSE 'procedure' END
ELSE null
END::text AS obj_type, pr.proname AS obj_name, pr.oid AS obj_oid, n.oid AS schema_oid, n.nspname AS schema_name, np.oid next_schema_oid, np.nspname next_schema_name,
pg_catalog.pg_get_function_identity_arguments(pr.oid) AS other_info
FROM pg_proc pr left join pg_namespace n
ON pr.pronamespace = n.oid left JOIN pg_namespace np
ON np.oid=n.nspparent left JOIN pg_type t
ON t.oid = pr.prorettype left JOIN pg_language l
ON l.oid = pr.prolang
WHERE NOT (t.typname = 'trigger' AND l.lanname = 'edbspl')
AND ({{ CATALOGS.DB_SUPPORT('n') }} AND {{ CATALOGS.DB_SUPPORT('np') }})
) fd
{% if not all_obj %}
WHERE fd.obj_type = '{{ obj_type }}'
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['event_trigger'] %}
select 'event_trigger'::text AS obj_type, evtname AS obj_name, ':event_trigger.'||oid||':/' || evtname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info from pg_event_trigger
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['schema'] %}
select 'schema'::text AS obj_type, n.nspname AS obj_name,
':schema.'||n.oid||':/' || n.nspname as obj_path, n.nspname AS schema_name,
{{ show_node_prefs['schema'] }} AS show_node, NULL AS other_info from pg_namespace n
where n.nspparent = 0
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['column'] %}
select 'column'::text AS obj_type, a.attname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/' ||
case
WHEN t.relkind in ('r', 'p') THEN ':table.'
WHEN t.relkind = 'v' THEN ':view.'
WHEN t.relkind = 'm' THEN ':mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:column.'|| a.attnum ||':/' || a.attname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['column'] }} AS show_node, NULL AS other_info
from pg_attribute a
inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','p','v','m')
left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0
and not t.relispartition
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['constraints', 'check_constraint', 'foreign_key', 'primary_key', 'unique_constraint', 'exclusion_constraint'] %}
SELECT
CASE
WHEN c.contype = 'c' THEN 'check_constraint'
WHEN c.contype = 'f' THEN 'foreign_key'
WHEN c.contype = 'p' THEN 'primary_key'
WHEN c.contype = 'u' THEN 'unique_constraint'
WHEN c.contype = 'x' THEN 'exclusion_constraint'
END::text AS obj_type,
case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_name,
':schema.'||n.oid||':/' || n.nspname||'/'||
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) ||
CASE
WHEN c.contype = 'c' THEN '/:check_constraint.' ||c.oid
WHEN c.contype = 'f' THEN '/:foreign_key.' ||c.conindid
WHEN c.contype = 'p' THEN '/:primary_key.' ||c.conindid
WHEN c.contype = 'u' THEN '/:unique_constraint.' ||c.conindid
WHEN c.contype = 'x' THEN '/:exclusion_constraint.' ||c.conindid
END ||':/'|| case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['constraints'] }} AS show_node, NULL AS other_info
from pg_constraint c
left join pg_class t on c.conrelid = t.oid
left join pg_class tf on c.confrelid = tf.oid
left join pg_namespace n on t.relnamespace = n.oid
where c.contypid = 0
{% if obj_type == 'check_constraint' %}
AND c.contype = 'c'
{% elif obj_type == 'foreign_key' %}
AND c.contype = 'f'
{% elif obj_type == 'primary_key' %}
AND c.contype = 'p'
{% elif obj_type == 'unique_constraint' %}
AND c.contype = 'u'
{% elif obj_type == 'exclusion_constraint' %}
AND c.contype = 'x'
{% else %}
AND c.contype IN ('c', 'f', 'p', 'u', 'x')
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['rule'] %}
select 'rule'::text AS obj_type, r.rulename AS obj_name, ':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end
||'/:rule.'||r.oid||':/'|| r.rulename AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['rule'] }} AS show_node, NULL AS other_info
from pg_rewrite r
left join pg_class t on r.ev_class = t.oid
left join pg_namespace n on t.relnamespace = n.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger'] %}
select 'trigger'::text AS obj_type, tr.tgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname||
case
WHEN t.relkind = 'r' THEN '/:table.'
when t.relkind = 'v' then '/:view.'
when t.relkind = 'm' then '/:mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:trigger.'|| tr.oid || ':/' || tr.tgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['trigger'] }} AS show_node, NULL AS other_info
from pg_trigger tr
left join pg_class t on tr.tgrelid = t.oid
left join pg_namespace n on t.relnamespace = n.oid
where tr.tgisinternal = false
and {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['type'] %}
SELECT 'type'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname ||
'/:type.'|| t.oid ||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['type'] }} AS show_node, NULL AS other_info
FROM pg_type t
LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_namespace n on t.typnamespace = n.oid
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%'
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['cast'] %}
SELECT 'cast'::text AS obj_type, format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_name,
':cast.'||ca.oid||':/' || format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['cast'] }} AS show_node, NULL AS other_info
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_type tt ON tt.oid=casttarget
{% if not show_system_objects %}
WHERE ca.oid > {{last_system_oid}}::OID
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['language'] %}
SELECT 'language'::text AS obj_type, lanname AS obj_name, ':language.'||lan.oid||':/' || lanname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['language'] }} AS show_node, NULL AS other_info
FROM pg_language lan
WHERE lanispl IS TRUE
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_configuration'] %}
SELECT 'fts_configuration'::text AS obj_type, cfg.cfgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:fts_configuration.'||cfg.oid||':/' || cfg.cfgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['fts_configuration'] }} AS show_node, NULL AS other_info
FROM pg_ts_config cfg
left join pg_namespace n on cfg.cfgnamespace = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_dictionary'] %}
SELECT 'fts_dictionary' AS obj_type, dict.dictname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_dictionary.'||dict.oid||':/' || dict.dictname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_dictionary'] }} AS show_node, NULL AS other_info
FROM pg_ts_dict dict
left join pg_namespace ns on dict.dictnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_parser'] %}
SELECT 'fts_parser' AS obj_type, prs.prsname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_parser.'||prs.oid||':/' || prs.prsname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_parser'] }} AS show_node, NULL AS other_info
FROM pg_ts_parser prs
left join pg_namespace ns on prs.prsnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_template'] %}
SELECT 'fts_template' AS obj_type, tmpl.tmplname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_template.'||tmpl.oid||':/' || tmpl.tmplname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_template'] }} AS show_node, NULL AS other_info
FROM pg_ts_template tmpl
left join pg_namespace ns on tmpl.tmplnamespace = ns.oid
AND {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain'] %}
select 'domain' AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['domain'] }} AS show_node, NULL AS other_info
from pg_type t
inner join pg_namespace n on t.typnamespace = n.oid
where t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain_constraints'] %}
SELECT 'domain_constraints' AS obj_type,
c.conname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname || '/:domain_constraints.'||c.oid||':/' || c.conname AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['domain_constraints'] }} AS show_node, NULL AS other_info
FROM pg_constraint c JOIN pg_type t
ON t.oid=contypid JOIN pg_namespace n
ON n.oid=t.typnamespace
WHERE t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_data_wrapper'] %}
select 'foreign_data_wrapper' AS obj_type, fdwname AS obj_name, ':foreign_data_wrapper.'||oid||':/' || fdwname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_data_wrapper'] }} AS show_node, NULL AS other_info
from pg_foreign_data_wrapper
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_server'] %}
select 'foreign_server' AS obj_type, sr.srvname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_server'] }} AS show_node, NULL AS other_info
from pg_foreign_server sr
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['user_mapping'] %}
select 'user_mapping' AS obj_type, ro.rolname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname || '/:user_mapping.'||ro.oid||':/' || ro.rolname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['user_mapping'] }} AS show_node, NULL AS other_info
from pg_user_mapping um
inner join pg_roles ro on um.umuser = ro.oid
inner join pg_foreign_server sr on um.umserver = sr.oid
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_table'] %}
select 'foreign_table' AS obj_type, c.relname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:foreign_table.'||c.oid||':/' || c.relname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['foreign_table'] }} AS show_node, NULL AS other_info
from pg_foreign_table ft
inner join pg_class c on ft.ftrelid = c.oid
inner join pg_namespace ns on c.relnamespace = ns.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['extension'] %}
select 'extension' AS obj_type, x.extname AS obj_name, ':extension.'||x.oid||':/' || x.extname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['extension'] }} AS show_node, NULL AS other_info
FROM pg_extension x
JOIN pg_namespace n on x.extnamespace=n.oid
join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['collation'] %}
SELECT 'collation' AS obj_type, c.collname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:collation.'||c.oid||':/' || c.collname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['collation'] }} AS show_node, NULL AS other_info
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['synonym'] %}
SELECT 'synonym' AS obj_type, s.synname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:synonym.'||s.oid||':/' || s.synname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['synonym'] }} AS show_node, NULL AS other_info
FROM pg_synonym s
JOIN pg_namespace n ON n.oid=s.synnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['package'] %}
SELECT 'package' AS obj_type, p.nspname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:package.'||p.oid||':/' || p.nspname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['package'] }} AS show_node, NULL AS other_info
FROM pg_namespace p
JOIN pg_namespace n ON n.oid=p.nspparent
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['edbvar'] %}
SELECT 'edbvar' AS obj_type, v.varname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/:package.'||p.oid||':/' || p.nspname || '/:edbvar.'||v.oid||':/' || v.varname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['edbvar'] }} AS show_node, NULL AS other_info
FROM edb_variable v JOIN pg_namespace p
ON v.varpackage = p.oid JOIN pg_namespace n
ON p.nspparent = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('p') }}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
{% if not show_system_objects %}
AND NOT ({{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }})
AND (sn.schema_name IS NOT NULL AND sn.schema_name NOT LIKE 'pg\_%')
{% endif %}
ORDER BY 1, 2, 3

View File

@@ -0,0 +1,516 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
{% set all_obj = false %}
{% if obj_type == 'all' or obj_type is none %}
{% set all_obj = true %}
{% endif %}
SELECT obj_type, obj_name,
REPLACE(obj_path, '/'||sn.schema_name||'/', '/'||{{ CATALOGS.LABELS_SCHEMACOL('sn.schema_name', _) }}||'/') AS obj_path,
schema_name, show_node, other_info,
CASE
WHEN {{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }} THEN
CASE WHEN {{ CATALOGS.DB_SUPPORT_SCHEMACOL('sn.schema_name') }} THEN 'D' ELSE 'O' END
ELSE 'N'
END AS catalog_level
FROM (
{% if all_obj or obj_type in ['sequence', 'view', 'mview'] %}
SELECT
CASE
WHEN c.relkind = 'S' THEN 'sequence'
WHEN c.relkind = 'v' THEN 'view'
WHEN c.relkind = 'm' THEN 'mview'
ELSE 'should not happen'
END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN c.relkind = 'S' THEN ':sequence.'
WHEN c.relkind = 'v' THEN ':view.'
WHEN c.relkind = 'm' THEN ':mview.'
ELSE 'should not happen'
END || c.oid ||':/' || c.relname AS obj_path, n.nspname AS schema_name,
CASE
WHEN c.relkind = 'S' THEN {{ show_node_prefs['sequence'] }}
WHEN c.relkind = 'v' THEN {{ show_node_prefs['view'] }}
WHEN c.relkind = 'm' THEN {{ show_node_prefs['mview'] }}
ELSE False
END AS show_node, NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
{% if all_obj %}
WHERE c.relkind in ('S','v','m')
{% elif obj_type == 'sequence' %}
WHERE c.relkind = 'S'
{% elif obj_type == 'view' %}
WHERE c.relkind = 'v'
{% elif obj_type == 'mview' %}
WHERE c.relkind = 'm'
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['table', 'partition'] %}
SELECT CASE WHEN c.relispartition THEN 'partition' ELSE 'table' END::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' || (
WITH RECURSIVE table_path_data as (
select c.oid as oid, 0 as height,
CASE c.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || c.oid || ':/' || c.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) obj_path, n.nspname AS schema_name,
CASE WHEN c.relispartition THEN {{ show_node_prefs['partition'] }}
ELSE {{ show_node_prefs['table'] }} END AS show_node,
NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind in ('p','r')
{% if obj_type == 'table' %}
AND NOT c.relispartition
{% elif obj_type == 'partition' %}
AND c.relispartition
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['index'] %}
SELECT 'index'::text AS obj_type, cls.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/:table.'|| tab.oid ||':/' || tab.relname || '/:index.'|| cls.oid ||':/' || cls.relname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
JOIN pg_namespace n ON n.oid=tab.relnamespace
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON des.objoid=cls.oid
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0)
WHERE contype IS NULL
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger_function', 'function', 'procedure', 'edbfunc', 'edbproc'] %}
SELECT fd.obj_type, fd.obj_name,
CASE
WHEN fd.obj_type = 'function' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:function.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'procedure' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:procedure.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'trigger_function' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:trigger_function.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'edbfunc' THEN
':schema.'|| fd.next_schema_oid || ':/' || fd.next_schema_name || '/:package.'|| fd.schema_oid || ':/' || fd.schema_name || '/:edbfunc.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'edbproc' THEN
':schema.'|| fd.next_schema_oid || ':/' || fd.next_schema_name || '/:package.'|| fd.schema_oid || ':/' || fd.schema_name || '/:edbproc.' || fd.obj_oid ||':/' || fd.obj_name
ELSE NULL
END AS obj_path,
CASE
WHEN fd.obj_type IN ('function', 'procedure', 'trigger_function') THEN fd.schema_name
WHEN fd.obj_type IN ('edbfunc', 'edbproc') THEN fd.next_schema_name
ELSE NULL
END AS schema_name,
CASE
WHEN fd.obj_type = 'function' THEN {{ show_node_prefs['function'] }}
WHEN fd.obj_type = 'procedure' THEN {{ show_node_prefs['procedure'] }}
WHEN fd.obj_type = 'trigger_function' THEN {{ show_node_prefs['trigger_function'] }}
WHEN fd.obj_type = 'edbfunc' THEN {{ show_node_prefs['edbfunc'] }}
WHEN fd.obj_type = 'edbproc' THEN {{ show_node_prefs['edbproc'] }}
ELSE NULL
END AS show_node, other_info
FROM (
SELECT
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN 'trigger_function'
WHEN pr.protype = '0'::char THEN
CASE WHEN np.oid IS NOT NULL THEN 'edbfunc' ELSE 'function' END
WHEN pr.protype = '1'::char THEN
CASE WHEN np.oid IS NOT NULL THEN 'edbproc' ELSE 'procedure' END
ELSE null
END::text AS obj_type, pr.proname AS obj_name, pr.oid AS obj_oid, n.oid AS schema_oid, n.nspname AS schema_name, np.oid next_schema_oid, np.nspname next_schema_name,
pg_catalog.pg_get_function_identity_arguments(pr.oid) AS other_info
FROM pg_proc pr left join pg_namespace n
ON pr.pronamespace = n.oid left JOIN pg_namespace np
ON np.oid=n.nspparent left JOIN pg_type t
ON t.oid = pr.prorettype left JOIN pg_language l
ON l.oid = pr.prolang
WHERE NOT (t.typname = 'trigger' AND l.lanname = 'edbspl')
AND ({{ CATALOGS.DB_SUPPORT('n') }} AND {{ CATALOGS.DB_SUPPORT('np') }})
) fd
{% if not all_obj %}
WHERE fd.obj_type = '{{ obj_type }}'
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['event_trigger'] %}
select 'event_trigger'::text AS obj_type, evtname AS obj_name, ':event_trigger.'||oid||':/' || evtname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info from pg_event_trigger
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['schema'] %}
select 'schema'::text AS obj_type, n.nspname AS obj_name,
':schema.'||n.oid||':/' || n.nspname as obj_path, n.nspname AS schema_name,
{{ show_node_prefs['schema'] }} AS show_node, NULL AS other_info from pg_namespace n
where n.nspparent = 0
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['column'] %}
select 'column'::text AS obj_type, a.attname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/' ||
case
WHEN t.relkind in ('r', 'p') THEN ':table.'
WHEN t.relkind = 'v' THEN ':view.'
WHEN t.relkind = 'm' THEN ':mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:column.'|| a.attnum ||':/' || a.attname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['column'] }} AS show_node, NULL AS other_info
from pg_attribute a
inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','p','v','m')
left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0
and not t.relispartition
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['constraints', 'check_constraint', 'foreign_key', 'primary_key', 'unique_constraint', 'exclusion_constraint'] %}
SELECT
CASE
WHEN c.contype = 'c' THEN 'check_constraint'
WHEN c.contype = 'f' THEN 'foreign_key'
WHEN c.contype = 'p' THEN 'primary_key'
WHEN c.contype = 'u' THEN 'unique_constraint'
WHEN c.contype = 'x' THEN 'exclusion_constraint'
END::text AS obj_type,
case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_name,
':schema.'||n.oid||':/' || n.nspname||'/'||
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
) ||
CASE
WHEN c.contype = 'c' THEN '/:check_constraint.' ||c.oid
WHEN c.contype = 'f' THEN '/:foreign_key.' ||c.conindid
WHEN c.contype = 'p' THEN '/:primary_key.' ||c.conindid
WHEN c.contype = 'u' THEN '/:unique_constraint.' ||c.conindid
WHEN c.contype = 'x' THEN '/:exclusion_constraint.' ||c.conindid
END ||':/'|| case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['constraints'] }} AS show_node, NULL AS other_info
from pg_constraint c
left join pg_class t on c.conrelid = t.oid
left join pg_class tf on c.confrelid = tf.oid
left join pg_namespace n on t.relnamespace = n.oid
where c.contypid = 0
{% if obj_type == 'check_constraint' %}
AND c.contype = 'c'
{% elif obj_type == 'foreign_key' %}
AND c.contype = 'f'
{% elif obj_type == 'primary_key' %}
AND c.contype = 'p'
{% elif obj_type == 'unique_constraint' %}
AND c.contype = 'u'
{% elif obj_type == 'exclusion_constraint' %}
AND c.contype = 'x'
{% else %}
AND c.contype IN ('c', 'f', 'p', 'u', 'x')
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['rule'] %}
select 'rule'::text AS obj_type, r.rulename AS obj_name, ':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end
||'/:rule.'||r.oid||':/'|| r.rulename AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['rule'] }} AS show_node, NULL AS other_info
from pg_rewrite r
left join pg_class t on r.ev_class = t.oid
left join pg_namespace n on t.relnamespace = n.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger', 'compound_trigger'] %}
select
CASE WHEN tr.tgpackageoid != 0 THEN 'compound_trigger' ELSE 'trigger' END::text AS obj_type, tr.tgname AS obj_name,
':schema.'||n.oid||':/' || n.nspname|| '/' ||
case
when t.relkind = 'v' then ':view.'
when t.relkind = 'm' then ':mview.'
WHEN t.relkind in ('r', 'p') THEN
(
WITH RECURSIVE table_path_data as (
select t.oid as oid, 0 as height,
CASE t.relispartition WHEN true THEN ':partition.' ELSE ':table.' END || t.oid || ':/' || t.relname as path
union
select rel.oid, pt.height+1 as height,
CASE rel.relispartition WHEN true THEN ':partition.' ELSE ':table.' END
|| rel.oid || ':/' || rel.relname || '/' || pt.path as path
from pg_class rel JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
join pg_inherits inh ON inh.inhparent = rel.oid
join table_path_data pt ON inh.inhrelid = pt.oid
)
select path from table_path_data order by height desc limit 1
)
end || CASE WHEN tr.tgpackageoid != 0 THEN '/:compound_trigger.' ELSE '/:trigger.' END || tr.oid || ':/' || tr.tgname AS obj_path, n.nspname AS schema_name,
CASE WHEN tr.tgpackageoid != 0 THEN {{ show_node_prefs['compound_trigger'] }} ELSE {{ show_node_prefs['trigger'] }} END AS show_node,
NULL AS other_info
from pg_trigger tr
left join pg_class t on tr.tgrelid = t.oid
left join pg_namespace n on t.relnamespace = n.oid
where tr.tgisinternal = false
and {{ CATALOGS.DB_SUPPORT('n') }}
{% if obj_type == 'compound_trigger' %}
AND tr.tgpackageoid != 0
{% elif obj_type == 'trigger' %}
AND tr.tgpackageoid = 0
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['type'] %}
SELECT 'type'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname ||
'/:type.'|| t.oid ||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['type'] }} AS show_node, NULL AS other_info
FROM pg_type t
LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_namespace n on t.typnamespace = n.oid
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%'
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['cast'] %}
SELECT 'cast'::text AS obj_type, format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_name,
':cast.'||ca.oid||':/' || format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['cast'] }} AS show_node, NULL AS other_info
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_type tt ON tt.oid=casttarget
{% if not show_system_objects %}
WHERE ca.oid > {{last_system_oid}}::OID
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['language'] %}
SELECT 'language'::text AS obj_type, lanname AS obj_name, ':language.'||lan.oid||':/' || lanname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['language'] }} AS show_node, NULL AS other_info
FROM pg_language lan
WHERE lanispl IS TRUE
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_configuration'] %}
SELECT 'fts_configuration'::text AS obj_type, cfg.cfgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:fts_configuration.'||cfg.oid||':/' || cfg.cfgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['fts_configuration'] }} AS show_node, NULL AS other_info
FROM pg_ts_config cfg
left join pg_namespace n on cfg.cfgnamespace = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_dictionary'] %}
SELECT 'fts_dictionary'::text AS obj_type, dict.dictname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_dictionary.'||dict.oid||':/' || dict.dictname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_dictionary'] }} AS show_node, NULL AS other_info
FROM pg_ts_dict dict
left join pg_namespace ns on dict.dictnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_parser'] %}
SELECT 'fts_parser'::text AS obj_type, prs.prsname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_parser.'||prs.oid||':/' || prs.prsname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_parser'] }} AS show_node, NULL AS other_info
FROM pg_ts_parser prs
left join pg_namespace ns on prs.prsnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_template'] %}
SELECT 'fts_template'::text AS obj_type, tmpl.tmplname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_template.'||tmpl.oid||':/' || tmpl.tmplname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_template'] }} AS show_node, NULL AS other_info
FROM pg_ts_template tmpl
left join pg_namespace ns on tmpl.tmplnamespace = ns.oid
AND {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain'] %}
select 'domain'::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['domain'] }} AS show_node, NULL AS other_info
from pg_type t
inner join pg_namespace n on t.typnamespace = n.oid
where t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain_constraints'] %}
SELECT 'domain_constraints'::text AS obj_type,
c.conname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname || '/:domain_constraints.'||c.oid||':/' || c.conname AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['domain_constraints'] }} AS show_node, NULL AS other_info
FROM pg_constraint c JOIN pg_type t
ON t.oid=contypid JOIN pg_namespace n
ON n.oid=t.typnamespace
WHERE t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_data_wrapper'] %}
select 'foreign_data_wrapper'::text AS obj_type, fdwname AS obj_name, ':foreign_data_wrapper.'||oid||':/' || fdwname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_data_wrapper'] }} AS show_node, NULL AS other_info
from pg_foreign_data_wrapper
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_server'] %}
select 'foreign_server' AS obj_type, sr.srvname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_server'] }} AS show_node, NULL AS other_info
from pg_foreign_server sr
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['user_mapping'] %}
select 'user_mapping' AS obj_type, ro.rolname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname || '/:user_mapping.'||ro.oid||':/' || ro.rolname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['user_mapping'] }} AS show_node, NULL AS other_info
from pg_user_mapping um
inner join pg_roles ro on um.umuser = ro.oid
inner join pg_foreign_server sr on um.umserver = sr.oid
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_table'] %}
select 'foreign_table' AS obj_type, c.relname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:foreign_table.'||c.oid||':/' || c.relname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['foreign_table'] }} AS show_node, NULL AS other_info
from pg_foreign_table ft
inner join pg_class c on ft.ftrelid = c.oid
inner join pg_namespace ns on c.relnamespace = ns.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['extension'] %}
select 'extension' AS obj_type, x.extname AS obj_name, ':extension.'||x.oid||':/' || x.extname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['extension'] }} AS show_node, NULL AS other_info
FROM pg_extension x
JOIN pg_namespace n on x.extnamespace=n.oid
join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['collation'] %}
SELECT 'collation' AS obj_type, c.collname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:collation.'||c.oid||':/' || c.collname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['collation'] }} AS show_node, NULL AS other_info
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['synonym'] %}
SELECT 'synonym' AS obj_type, s.synname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:synonym.'||s.oid||':/' || s.synname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['synonym'] }} AS show_node, NULL AS other_info
FROM pg_synonym s
JOIN pg_namespace n ON n.oid=s.synnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['package'] %}
SELECT 'package' AS obj_type, p.nspname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:package.'||p.oid||':/' || p.nspname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['package'] }} AS show_node, NULL AS other_info
FROM pg_namespace p
JOIN pg_namespace n ON n.oid=p.nspparent
WHERE p.nspcompoundtrigger = false
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['edbvar'] %}
SELECT 'edbvar' AS obj_type, v.varname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/:package.'||p.oid||':/' || p.nspname || '/:edbvar.'||v.oid||':/' || v.varname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['edbvar'] }} AS show_node, NULL AS other_info
FROM edb_variable v JOIN pg_namespace p
ON v.varpackage = p.oid JOIN pg_namespace n
ON p.nspparent = n.oid
WHERE p.nspcompoundtrigger = false
AND {{ CATALOGS.DB_SUPPORT('p') }}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
{% if not show_system_objects %}
AND NOT ({{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }})
AND (sn.schema_name IS NOT NULL AND sn.schema_name NOT LIKE 'pg\_%')
{% endif %}
ORDER BY 1, 2, 3

View File

@@ -0,0 +1,437 @@
{% import 'catalog/ppas/macros/catalogs.sql' as CATALOGS %}
{% set all_obj = false %}
{% if obj_type == 'all' or obj_type is none %}
{% set all_obj = true %}
{% endif %}
SELECT obj_type, obj_name,
REPLACE(obj_path, '/'||sn.schema_name||'/', '/'||{{ CATALOGS.LABELS_SCHEMACOL('sn.schema_name', _) }}||'/') AS obj_path,
schema_name, show_node, other_info,
CASE
WHEN {{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }} THEN
CASE WHEN {{ CATALOGS.DB_SUPPORT_SCHEMACOL('sn.schema_name') }} THEN 'D' ELSE 'O' END
ELSE 'N'
END AS catalog_level
FROM (
{% if all_obj or obj_type in ['table', 'sequence', 'view', 'mview'] %}
SELECT
CASE
WHEN c.relkind = 'r' THEN 'table'
WHEN c.relkind = 'S' THEN 'sequence'
WHEN c.relkind = 'v' THEN 'view'
WHEN c.relkind = 'm' THEN 'mview'
ELSE 'should not happen'
END::text::text AS obj_type, c.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/' ||
CASE
WHEN c.relkind = 'r' THEN ':table.'
WHEN c.relkind = 'S' THEN ':sequence.'
WHEN c.relkind = 'v' THEN ':view.'
WHEN c.relkind = 'm' THEN ':mview.'
ELSE 'should not happen'
END || c.oid ||':/' || c.relname AS obj_path, n.nspname AS schema_name,
CASE
WHEN c.relkind = 'r' THEN {{ show_node_prefs['table'] }}
WHEN c.relkind = 'S' THEN {{ show_node_prefs['sequence'] }}
WHEN c.relkind = 'v' THEN {{ show_node_prefs['view'] }}
WHEN c.relkind = 'm' THEN {{ show_node_prefs['mview'] }}
ELSE False
END AS show_node, NULL AS other_info
FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
{% if all_obj %}
WHERE c.relkind in ('r','S','v','m')
{% elif obj_type == 'table' %}
WHERE c.relkind = 'r'
{% elif obj_type == 'sequence' %}
WHERE c.relkind = 'S'
{% elif obj_type == 'view' %}
WHERE c.relkind = 'v'
{% elif obj_type == 'mview' %}
WHERE c.relkind = 'm'
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['index'] %}
SELECT 'index'::text::text AS obj_type, cls.relname AS obj_name,
':schema.'|| n.oid || ':/' || n.nspname || '/:table.'|| tab.oid ||':/' || tab.relname || '/:index.'|| cls.oid ||':/' || cls.relname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info
FROM pg_index idx
JOIN pg_class cls ON cls.oid=indexrelid
JOIN pg_class tab ON tab.oid=indrelid
JOIN pg_namespace n ON n.oid=tab.relnamespace
LEFT JOIN pg_depend dep ON (dep.classid = cls.tableoid AND dep.objid = cls.oid AND dep.refobjsubid = '0' AND dep.refclassid=(SELECT oid FROM pg_class WHERE relname='pg_constraint') AND dep.deptype='i')
LEFT OUTER JOIN pg_constraint con ON (con.tableoid = dep.refclassid AND con.oid = dep.refobjid)
LEFT OUTER JOIN pg_description des ON des.objoid=cls.oid
LEFT OUTER JOIN pg_description desp ON (desp.objoid=con.oid AND desp.objsubid = 0)
WHERE contype IS NULL
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger_function', 'function', 'procedure', 'edbfunc', 'edbproc'] %}
SELECT fd.obj_type, fd.obj_name,
CASE
WHEN fd.obj_type = 'function' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:function.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'procedure' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:procedure.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'trigger_function' THEN
':schema.'|| fd.schema_oid || ':/' || fd.schema_name || '/:trigger_function.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'edbfunc' THEN
':schema.'|| fd.next_schema_oid || ':/' || fd.next_schema_name || '/:package.'|| fd.schema_oid || ':/' || fd.schema_name || '/:edbfunc.' || fd.obj_oid ||':/' || fd.obj_name
WHEN fd.obj_type = 'edbproc' THEN
':schema.'|| fd.next_schema_oid || ':/' || fd.next_schema_name || '/:package.'|| fd.schema_oid || ':/' || fd.schema_name || '/:edbproc.' || fd.obj_oid ||':/' || fd.obj_name
ELSE NULL
END AS obj_path,
CASE
WHEN fd.obj_type IN ('function', 'procedure', 'trigger_function') THEN fd.schema_name
WHEN fd.obj_type IN ('edbfunc', 'edbproc') THEN fd.next_schema_name
ELSE NULL
END AS schema_name,
CASE
WHEN fd.obj_type = 'function' THEN {{ show_node_prefs['function'] }}
WHEN fd.obj_type = 'procedure' THEN {{ show_node_prefs['procedure'] }}
WHEN fd.obj_type = 'trigger_function' THEN {{ show_node_prefs['trigger_function'] }}
WHEN fd.obj_type = 'edbfunc' THEN {{ show_node_prefs['edbfunc'] }}
WHEN fd.obj_type = 'edbproc' THEN {{ show_node_prefs['edbproc'] }}
ELSE NULL
END AS show_node, other_info
FROM (
SELECT
CASE
WHEN t.typname IN ('trigger', 'event_trigger') THEN 'trigger_function'
WHEN pr.protype = '0'::char THEN
CASE WHEN np.oid IS NOT NULL THEN 'edbfunc' ELSE 'function' END
WHEN pr.protype = '1'::char THEN
CASE WHEN np.oid IS NOT NULL THEN 'edbproc' ELSE 'procedure' END
ELSE null
END::text::text AS obj_type, pr.proname AS obj_name, pr.oid AS obj_oid, n.oid AS schema_oid, n.nspname AS schema_name, np.oid next_schema_oid, np.nspname next_schema_name,
pg_catalog.pg_get_function_identity_arguments(pr.oid) AS other_info
FROM pg_proc pr left join pg_namespace n
ON pr.pronamespace = n.oid left JOIN pg_namespace np
ON np.oid=n.nspparent left JOIN pg_type t
ON t.oid = pr.prorettype left JOIN pg_language l
ON l.oid = pr.prolang
WHERE NOT (t.typname = 'trigger' AND l.lanname = 'edbspl')
AND ({{ CATALOGS.DB_SUPPORT('n') }} AND {{ CATALOGS.DB_SUPPORT('np') }})
) fd
{% if not all_obj %}
WHERE fd.obj_type = '{{ obj_type }}'
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['event_trigger'] %}
select 'event_trigger'::text::text AS obj_type, evtname AS obj_name, ':event_trigger.'||oid||':/' || evtname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['index'] }} AS show_node, NULL AS other_info from pg_event_trigger
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['schema'] %}
select 'schema'::text::text AS obj_type, n.nspname AS obj_name,
':schema.'||n.oid||':/' || n.nspname as obj_path, n.nspname AS schema_name,
{{ show_node_prefs['schema'] }} AS show_node, NULL AS other_info from pg_namespace n
where n.nspparent = 0
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['column'] %}
select 'column'::text::text AS obj_type, a.attname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/' ||
case
WHEN t.relkind = 'r' THEN ':table.'
WHEN t.relkind = 'v' THEN ':view.'
WHEN t.relkind = 'm' THEN ':mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:column.'|| a.attnum ||':/' || a.attname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['column'] }} AS show_node, NULL AS other_info
from pg_attribute a
inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','v','m')
left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['constraints', 'check_constraint', 'foreign_key', 'primary_key', 'unique_constraint', 'exclusion_constraint'] %}
SELECT
CASE
WHEN c.contype = 'c' THEN 'check_constraint'
WHEN c.contype = 'f' THEN 'foreign_key'
WHEN c.contype = 'p' THEN 'primary_key'
WHEN c.contype = 'u' THEN 'unique_constraint'
WHEN c.contype = 'x' THEN 'exclusion_constraint'
END::text::text AS obj_type,
case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_name,
':schema.'||n.oid||':/' || n.nspname||'/:table.'|| t.oid || ':/'||t.relname||
CASE
WHEN c.contype = 'c' THEN '/:check_constraint.' ||c.oid
WHEN c.contype = 'f' THEN '/:foreign_key.' ||c.conindid
WHEN c.contype = 'p' THEN '/:primary_key.' ||c.conindid
WHEN c.contype = 'u' THEN '/:unique_constraint.' ||c.conindid
WHEN c.contype = 'x' THEN '/:exclusion_constraint.' ||c.conindid
END ||':/'|| case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['constraints'] }} AS show_node, NULL AS other_info
from pg_constraint c
left join pg_class t on c.conrelid = t.oid
left join pg_class tf on c.confrelid = tf.oid
left join pg_namespace n on t.relnamespace = n.oid
where c.contypid = 0
{% if obj_type == 'check_constraint' %}
AND c.contype = 'c'
{% elif obj_type == 'foreign_key' %}
AND c.contype = 'f'
{% elif obj_type == 'primary_key' %}
AND c.contype = 'p'
{% elif obj_type == 'unique_constraint' %}
AND c.contype = 'u'
{% elif obj_type == 'exclusion_constraint' %}
AND c.contype = 'x'
{% else %}
AND c.contype IN ('c', 'f', 'p', 'u', 'x')
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['rule'] %}
select 'rule'::text::text AS obj_type, r.rulename AS obj_name, ':schema.'||n.oid||':/' || n.nspname||
case
WHEN t.relkind = 'r' THEN '/:table.'
when t.relkind = 'v' then '/:view.'
when t.relkind = 'm' then '/:mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname ||'/:rule.'||r.oid||':/'|| r.rulename AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['rule'] }} AS show_node, NULL AS other_info
from pg_rewrite r
left join pg_class t on r.ev_class = t.oid
left join pg_namespace n on t.relnamespace = n.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['trigger'] %}
select 'trigger'::text::text AS obj_type, tr.tgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname||
case
WHEN t.relkind = 'r' THEN '/:table.'
when t.relkind = 'v' then '/:view.'
when t.relkind = 'm' then '/:mview.'
else 'should not happen'
end || t.oid || ':/' || t.relname || '/:trigger.'|| tr.oid || ':/' || tr.tgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['trigger'] }} AS show_node, NULL AS other_info
from pg_trigger tr
left join pg_class t on tr.tgrelid = t.oid
left join pg_namespace n on t.relnamespace = n.oid
where tr.tgisinternal = false
and {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['type'] %}
SELECT 'type'::text::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname ||
'/:type.'|| t.oid ||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['type'] }} AS show_node, NULL AS other_info
FROM pg_type t
LEFT OUTER JOIN pg_type e ON e.oid=t.typelem
LEFT OUTER JOIN pg_class ct ON ct.oid=t.typrelid AND ct.relkind <> 'c'
LEFT OUTER JOIN pg_namespace n on t.typnamespace = n.oid
WHERE t.typtype != 'd' AND t.typname NOT LIKE E'\\_%'
{% if not show_system_objects %}
AND ct.oid is NULL
{% endif %}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['cast'] %}
SELECT 'cast'::text::text AS obj_type, format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_name,
':cast.'||ca.oid||':/' || format_type(st.oid,NULL) ||'->'|| format_type(tt.oid,tt.typtypmod) AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['cast'] }} AS show_node, NULL AS other_info
FROM pg_cast ca
JOIN pg_type st ON st.oid=castsource
JOIN pg_type tt ON tt.oid=casttarget
{% if not show_system_objects %}
WHERE ca.oid > {{last_system_oid}}::OID
{% endif %}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['language'] %}
SELECT 'language'::text::text AS obj_type, lanname AS obj_name, ':language.'||lan.oid||':/' || lanname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['language'] }} AS show_node, NULL AS other_info
FROM pg_language lan
WHERE lanispl IS TRUE
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_configuration'] %}
SELECT 'fts_configuration'::text::text AS obj_type, cfg.cfgname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:fts_configuration.'||cfg.oid||':/' || cfg.cfgname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['fts_configuration'] }} AS show_node, NULL AS other_info
FROM pg_ts_config cfg
left join pg_namespace n on cfg.cfgnamespace = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_dictionary'] %}
SELECT 'fts_dictionary'::text::text AS obj_type, dict.dictname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_dictionary.'||dict.oid||':/' || dict.dictname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_dictionary'] }} AS show_node, NULL AS other_info
FROM pg_ts_dict dict
left join pg_namespace ns on dict.dictnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_parser'] %}
SELECT 'fts_parser'::text::text AS obj_type, prs.prsname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_parser.'||prs.oid||':/' || prs.prsname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_parser'] }} AS show_node, NULL AS other_info
FROM pg_ts_parser prs
left join pg_namespace ns on prs.prsnamespace = ns.oid
WHERE {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['fts_template'] %}
SELECT 'fts_template'::text::text AS obj_type, tmpl.tmplname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:fts_template.'||tmpl.oid||':/' || tmpl.tmplname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['fts_template'] }} AS show_node, NULL AS other_info
FROM pg_ts_template tmpl
left join pg_namespace ns on tmpl.tmplnamespace = ns.oid
AND {{ CATALOGS.DB_SUPPORT('ns') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain'] %}
select 'domain'::text::text AS obj_type, t.typname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['domain'] }} AS show_node, NULL AS other_info
from pg_type t
inner join pg_namespace n on t.typnamespace = n.oid
where t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['domain_constraints'] %}
SELECT 'domain_constraints'::text::text AS obj_type,
c.conname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:domain.'||t.oid||':/' || t.typname || '/:domain_constraints.'||c.oid||':/' || c.conname AS obj_path,
n.nspname AS schema_name,
{{ show_node_prefs['domain_constraints'] }} AS show_node, NULL AS other_info
FROM pg_constraint c JOIN pg_type t
ON t.oid=contypid JOIN pg_namespace n
ON n.oid=t.typnamespace
WHERE t.typtype = 'd'
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_data_wrapper'] %}
select 'foreign_data_wrapper'::text AS obj_type, fdwname AS obj_name, ':foreign_data_wrapper.'||oid||':/' || fdwname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_data_wrapper'] }} AS show_node, NULL AS other_info
from pg_foreign_data_wrapper
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_server'] %}
select 'foreign_server'::text AS obj_type, sr.srvname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['foreign_server'] }} AS show_node, NULL AS other_info
from pg_foreign_server sr
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['user_mapping'] %}
select 'user_mapping'::text AS obj_type, ro.rolname AS obj_name, ':foreign_data_wrapper.'||fdw.oid||':/' || fdw.fdwname || '/:foreign_server.'||sr.oid||':/' || sr.srvname || '/:user_mapping.'||ro.oid||':/' || ro.rolname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['user_mapping'] }} AS show_node, NULL AS other_info
from pg_user_mapping um
inner join pg_roles ro on um.umuser = ro.oid
inner join pg_foreign_server sr on um.umserver = sr.oid
inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['foreign_table'] %}
select 'foreign_table'::text AS obj_type, c.relname AS obj_name, ':schema.'||ns.oid||':/' || ns.nspname || '/:foreign_table.'||c.oid||':/' || c.relname AS obj_path, ns.nspname AS schema_name,
{{ show_node_prefs['foreign_table'] }} AS show_node, NULL AS other_info
from pg_foreign_table ft
inner join pg_class c on ft.ftrelid = c.oid
inner join pg_namespace ns on c.relnamespace = ns.oid
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['extension'] %}
select 'extension'::text AS obj_type, x.extname AS obj_name, ':extension.'||x.oid||':/' || x.extname AS obj_path, ''::text AS schema_name,
{{ show_node_prefs['extension'] }} AS show_node, NULL AS other_info
FROM pg_extension x
JOIN pg_namespace n on x.extnamespace=n.oid
join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['collation'] %}
SELECT 'collation'::text AS obj_type, c.collname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:collation.'||c.oid||':/' || c.collname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['collation'] }} AS show_node, NULL AS other_info
FROM pg_collation c
JOIN pg_namespace n ON n.oid=c.collnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['synonym'] %}
SELECT 'synonym'::text AS obj_type, s.synname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:synonym.'||s.oid||':/' || s.synname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['synonym'] }} AS show_node, NULL AS other_info
FROM pg_synonym s
JOIN pg_namespace n ON n.oid=s.synnamespace
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['package'] %}
SELECT 'package'::text AS obj_type, p.nspname AS obj_name, ':schema.'||n.oid||':/' || n.nspname || '/:package.'||p.oid||':/' || p.nspname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['package'] }} AS show_node, NULL AS other_info
FROM pg_namespace p
JOIN pg_namespace n ON n.oid=p.nspparent
WHERE {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
{% if all_obj %}
UNION
{% endif %}
{% if all_obj or obj_type in ['edbvar'] %}
SELECT 'edbvar'::text AS obj_type, v.varname AS obj_name,
':schema.'||n.oid||':/' || n.nspname || '/:package.'||p.oid||':/' || p.nspname || '/:edbvar.'||v.oid||':/' || v.varname AS obj_path, n.nspname AS schema_name,
{{ show_node_prefs['edbvar'] }} AS show_node, NULL AS other_info
FROM edb_variable v JOIN pg_namespace p
ON v.varpackage = p.oid JOIN pg_namespace n
ON p.nspparent = n.oid
WHERE {{ CATALOGS.DB_SUPPORT('p') }}
AND {{ CATALOGS.DB_SUPPORT('n') }}
{% endif %}
) sn
where lower(sn.obj_name) like '%{{ search_text }}%'
{% if not show_system_objects %}
AND NOT ({{ CATALOGS.IS_CATALOG_SCHEMA('sn.schema_name') }})
AND (sn.schema_name IS NOT NULL AND sn.schema_name NOT LIKE 'pg\_%')
{% endif %}
ORDER BY 1, 2, 3

View File

@@ -0,0 +1,75 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from __future__ import print_function
import sys
import json
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from regression.python_test_utils import test_utils as utils
try:
from urllib import urlencode
except Exception as e:
from urllib.parse import urlencode
class SearchObjectsApiSearch(BaseTestGenerator):
""" This class will test search API of search objects. """
scenarios = [
('Search with all types', dict(text='emp', type='all', singles=False)),
('Search with None types', dict(text='emp', type=None, singles=False)),
('Search for all single types',
dict(text='emp', type=None, singles=True)),
]
def runFor(self, text=None, type=None):
url_params = dict(
text=text
)
if type is not None:
url_params['type'] = type
url_params = urlencode(url_params)
response = self.tester.get(self.base_url + '?' + url_params)
self.assertEquals(response.status_code, 200)
def runTest(self):
database_info = parent_node_dict["database"][-1]
server_id = database_info["server_id"]
db_id = database_info["db_id"]
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
server_id,
db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database to add the schema.")
self.base_url = '/search_objects/search/' \
+ str(server_id) + '/' + str(db_id)
if not self.singles:
self.runFor(text=self.text, type=self.type)
else:
# test for all the node types individually
types_url = '/search_objects/types/' +\
str(server_id) + '/' + str(db_id)
response = self.tester.get(types_url)
self.assertEquals(response.status_code, 200)
types_data = json.loads(response.data.decode('utf-8'))['data']
for a_type in types_data:
print('Running search for type {0}'.format(a_type),
file=sys.stderr)
self.runFor(text=self.text, type=a_type)

View File

@@ -0,0 +1,47 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
import json
from pgadmin.utils.route import BaseTestGenerator
from regression import parent_node_dict
from pgadmin.browser.server_groups.servers.databases.tests import utils as \
database_utils
from regression.python_test_utils import test_utils as utils
class SearchObjectsApiTypes(BaseTestGenerator):
""" This class will test types API of search objects. """
scenarios = [
# Fetching default URL for schema node.
('Types API URL', dict(url='/search_objects/types'))
]
def runTest(self):
database_info = parent_node_dict["database"][-1]
server_id = database_info["server_id"]
db_id = database_info["db_id"]
db_con = database_utils.connect_database(self,
utils.SERVER_GROUP,
server_id,
db_id)
if not db_con["info"] == "Database connected.":
raise Exception("Could not connect to database to add the schema.")
url = self.url + '/' + str(server_id) + '/' + str(db_id)
response = self.tester.get(url)
self.assertEquals(response.status_code, 200)
# repsonse data should be dict
response_data = json.loads(response.data.decode('utf-8'))['data']
self.assertEquals(type(response_data), dict)
# response data key values should not be None
for key, value in response_data.items():
self.assertIsNotNone(value, 'Key {0} has value None'.format(key))

View File

@@ -0,0 +1,117 @@
import sys
from pgadmin.tools.search_objects.utils import SearchObjectsHelper, current_app
from pgadmin.utils.route import BaseTestGenerator
if sys.version_info < (3, 3):
from mock import patch, MagicMock
else:
from unittest.mock import patch, MagicMock
class SearchObjectsHelperTest(BaseTestGenerator):
scenarios = [
('scenario', dict(
node_blueprints=[
dict(node_type='table', coll_label='Tables',
backend_supported=True),
dict(node_type='view', coll_label='Views',
backend_supported=False),
dict(node_type='index', coll_label='Indexes',
backend_supported=True),
dict(node_type='role', coll_label='Roles',
backend_supported=True)
],
all_node_types=['table', 'view', 'index'],
expected_show_node_prefs=dict(table=True, view=False, index=True),
expected_supported_types=dict(table='Tables', index='Indexes'),
expected_supported_types_skip=dict(table='Tables', view='Views',
index='Indexes'),
execute_dict_return_value=(
True, dict(rows=[
dict(obj_name='name1', obj_type='table',
obj_path='some/path', show_node=True,
other_info=None, catalog_level='N'),
dict(obj_name='name2', obj_type='view',
obj_path='some1/path', show_node=True,
other_info=None, catalog_level='D'),
dict(obj_name='name3', obj_type='index',
obj_path='some2/path1', show_node=True,
other_info='oid', catalog_level='O'),
])),
expected_search_op=(
True, [
dict(name='name1', type='table', type_label='Tables',
path='some/path',
show_node=True, other_info=None, catalog_level='N'),
dict(name='name2', type='view', type_label='Views',
path='some1/path',
show_node=True, other_info=None, catalog_level='D'),
dict(name='name3', type='index', type_label='Indexes',
path='some2/path1',
show_node=True, other_info='oid', catalog_level='O'),
]
)
))
]
def __create_manager(self):
connection = MagicMock(
execute_dict=MagicMock(),
db='somedb'
)
connection.execute_dict.return_value = self.execute_dict_return_value
def connection_function(did):
return connection
return MagicMock(
connection=connection_function
)
@patch('pgadmin.tools.search_objects.utils.get_node_blueprint')
@patch('pgadmin.tools.search_objects.utils.get_driver')
def runTest(self, get_driver_mock, get_node_blueprint_mock):
manager = self.__create_manager()
get_driver_mock.return_value = MagicMock(
connection_manager=lambda session_id: manager)
def __get_node_blueprint_mock(node_type):
blueprints = self.node_blueprints
blueprint = None
for data in blueprints:
if node_type == data['node_type']:
blueprint = MagicMock(
BackendSupported=MagicMock(
return_value=data['backend_supported']),
collection_label=data['coll_label'],
show_node=data['backend_supported'],
)
return blueprint
get_node_blueprint_mock.side_effect = __get_node_blueprint_mock
with self.app.app_context():
so_obj = SearchObjectsHelper(2, 18456,
node_types=self.all_node_types)
so_obj.get_sql = MagicMock(return_value='dummy query')
# test template path
manager.server_type = 'pg'
manager.version = 906000
self.assertEquals(so_obj.get_template_path(),
'search_objects/sql/pg/#906000#')
self.assertEquals(so_obj.get_show_node_prefs(),
self.expected_show_node_prefs)
self.assertEquals(so_obj.get_supported_types(),
self.expected_supported_types)
self.assertEquals(so_obj.get_supported_types(skip_check=True),
self.expected_supported_types_skip)
self.assertEquals(so_obj.search('searchtext', 'all'),
self.expected_search_op)

View File

@@ -0,0 +1,131 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2020, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
from flask import current_app, render_template
from flask_babelex import gettext
from pgadmin.utils.driver import get_driver
from config import PG_DEFAULT_DRIVER
def get_node_blueprint(node_type):
blueprint = None
node_type = 'NODE-' + node_type
if node_type in current_app.blueprints:
blueprint = current_app.blueprints[node_type]
return blueprint
class SearchObjectsHelper:
def __init__(self, sid, did, show_system_objects=False, node_types=None):
self.sid = sid
self.did = did
self.show_system_objects = show_system_objects
self.manager = get_driver(
PG_DEFAULT_DRIVER
).connection_manager(sid)
self._all_node_types = [
'cast', 'fts_dictionary', 'check_constraint',
'exclusion_constraint', 'foreign_key',
'primary_key', 'unique_constraint', 'constraints', 'trigger',
'table', 'compound_trigger', 'rule', 'column', 'partition',
'index', 'type', 'domain', 'domain_constraints', 'schema',
'synonym', 'sequence', 'edbvar', 'edbfunc', 'edbproc', 'package',
'foreign_table', 'fts_parser', 'function', 'procedure',
'trigger_function', 'fts_template', 'collation', 'view', 'mview',
'fts_configuration', 'extension', 'language',
'event_trigger', 'foreign_server', 'user_mapping',
'foreign_data_wrapper'
] if node_types is None else node_types
@property
def all_node_types(self):
return self._all_node_types
def get_template_path(self):
return 'search_objects/sql/{0}/#{1}#'.format(
self.manager.server_type, self.manager.version)
def get_show_node_prefs(self):
return_types = {}
for node_type in self.all_node_types:
blueprint = get_node_blueprint(node_type)
if blueprint is None:
continue
return_types[node_type] = blueprint.show_node
return return_types
def get_supported_types(self, skip_check=False):
return_types = {}
for node_type in self.all_node_types:
blueprint = get_node_blueprint(node_type)
if blueprint is None:
continue
if blueprint.BackendSupported(self.manager, is_catalog=False,
did=self.did) or skip_check:
if node_type in ['edbfunc', 'edbproc']:
return_types[node_type] =\
gettext('Package {0}').format(
blueprint.collection_label)
else:
return_types[node_type] = blueprint.collection_label
return return_types
def get_sql(self, sql_file, **kwargs):
return render_template(
"/".join([self.get_template_path(), sql_file]),
**kwargs
)
def finalize_id_path(self, path, base_path):
if base_path is not None:
path = '{0}/{1}'.format(base_path, path)
return path
def search(self, text, obj_type=None):
conn = self.manager.connection(did=self.did)
last_system_oid = (self.manager.db_info[self.did])['datlastsysoid'] \
if self.manager.db_info is not None and self.did in \
self.manager.db_info else 0
show_node_prefs = self.get_show_node_prefs()
node_labels = self.get_supported_types(skip_check=True)
# Column catalog_level has values as
# N - Not a catalog schema
# D - Catalog schema with DB support - pg_catalog
# O - Catalog schema with object support only - info schema, dbo, sys
status, res = conn.execute_dict(
self.get_sql('search.sql', search_text=text, obj_type=obj_type,
show_system_objects=self.show_system_objects,
show_node_prefs=show_node_prefs, _=gettext,
last_system_oid=last_system_oid)
)
if not status:
return status, res
ret_val = [
{
'name': row['obj_name'],
'type': row['obj_type'],
'type_label': node_labels[row['obj_type']],
'path': row['obj_path'],
'show_node': row['show_node'],
'other_info': row['other_info'],
'catalog_level': row['catalog_level'],
}
for row in res['rows']
]
return True, ret_val

View File

@@ -112,7 +112,7 @@ li {
font-size: 9pt;
}
.slick-header-column.ui-state-default {
#datagrid .slick-header-column.ui-state-default {
height: 32px !important;
}

View File

@@ -19,5 +19,7 @@ define(function () {
'datagrid.initialize_query_tool_with_did': '/initialize/query_tool/<int:sgid>/<int:sid>/<int:did>',
'restore.create_job': '/restore/job/<int:sid>',
'datagrid.panel': '/panel/<int:trans_id>',
'search_objects.types': '/search_objects/types/<int:sid>/<int:did>',
'search_objects.search': '/search_objects/search/<int:sid>/<int:did>',
};
});

View File

@@ -0,0 +1,155 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import SearchObjectsDialog from 'tools/search_objects/static/js/search_objects_dialog';
import {TreeFake} from '../tree/tree_fake';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios/index';
const context = describe;
describe('SearchObjectsDialog', () => {
let soDialog;
let pgBrowser;
let jquerySpy;
let alertifySpy;
beforeEach(() => {
pgBrowser = {
treeMenu: new TreeFake(),
Nodes: {
server: {
hasId: true,
label: 'server',
getTreeNodeHierarchy: jasmine.createSpy('server.getTreeNodeHierarchy'),
},
database: {
hasId: true,
label: 'database',
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
},
schema: {
hasId: true,
label: 'schema',
getTreeNodeHierarchy: jasmine.createSpy('db.getTreeNodeHierarchy'),
},
},
stdW: {
sm: 500,
md: 700,
lg: 900,
default: 500,
},
stdH: {
sm: 200,
md: 400,
lg: 550,
default: 550,
},
};
pgBrowser.Nodes.server.hasId = true;
pgBrowser.Nodes.database.hasId = true;
jquerySpy = jasmine.createSpy('jquerySpy');
const hierarchy = {
children: [
{
id: 'root',
children: [
{
id: 'serverTreeNode',
data: {
_id: 10,
_type: 'server',
user: {name: 'username'},
label: 'theserver',
},
children: [
{
id: 'some_database',
data: {
_type: 'database',
_id: 11,
label: 'thedatabase',
},
},
],
},
{
id: 'ppasServer',
data: {
_type: 'server',
server_type: 'ppas',
children: [
{id: 'someNodeUnderneathPPASServer'},
],
},
},
],
},
],
};
pgBrowser.treeMenu = TreeFake.build(hierarchy);
});
describe('#draw', () => {
let networkMock;
beforeEach(() => {
networkMock = new MockAdapter(axios);
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
alertifySpy['search_objects'] = jasmine.createSpy('search_objects');
soDialog = new SearchObjectsDialog(
pgBrowser,
jquerySpy,
alertifySpy,
null
);
pgBrowser.get_preference = jasmine.createSpy('get_preferences');
});
afterEach(() => {
networkMock.restore();
});
context('there are no ancestors of the type database', () => {
it('does not create a dialog', () => {
pgBrowser.treeMenu.selectNode([{id: 'serverTreeNode'}]);
soDialog.draw(null, null, null);
expect(alertifySpy['search_objects']).not.toHaveBeenCalled();
});
it('display an alert with a Backup Error', () => {
soDialog.draw(null, [{id: 'serverTreeNode'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Search Objects Error',
'Please select a database or its child node from the browser.'
);
});
});
context('there is an ancestor of the type database', () => {
let soDialogResizeToSpy;
beforeEach(() => {
soDialogResizeToSpy = jasmine.createSpyObj('soDialogResizeToSpy', ['resizeTo']);
alertifySpy['search_objects'].and
.returnValue(soDialogResizeToSpy);
});
it('displays the dialog when database node selected', (done) => {
soDialog.draw(null, [{id: 'some_database'}], null, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['search_objects']).toHaveBeenCalledWith('Search Objects - thedatabase/username@theserver');
expect(soDialogResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
});
});

View File

@@ -0,0 +1,545 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2020, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////
import {TreeFake} from '../tree/tree_fake';
import SearchObjectsDialogWrapper from 'tools/search_objects/static/js/search_objects_dialog_wrapper';
import axios from 'axios/index';
import MockAdapter from 'axios-mock-adapter';
import {TreeNode} from '../../../pgadmin/static/js/tree/tree';
let context = describe;
describe('SearchObjectsDialogWrapper', () => {
let jquerySpy;
let pgBrowser;
let alertifySpy;
let dialogModelKlassSpy = null;
let backform;
let soDialogWrapper;
let noDataNode;
let serverTreeNode;
let databaseTreeNode;
let viewSchema;
let soJQueryContainerSpy;
let soNodeChildNodeSpy;
let soNode;
beforeEach(() => {
pgBrowser = {
treeMenu: new TreeFake(),
Nodes: {
server: {
hasId: true,
getTreeNodeHierarchy: jasmine.createSpy('getTreeNodeHierarchy'),
},
database: {
hasId: true,
getTreeNodeHierarchy: jasmine.createSpy('getTreeNodeHierarchy'),
},
'coll-sometype': {
type: 'coll-sometype',
hasId: false,
label: 'Some types coll',
},
sometype: {
type: 'sometype',
hasId: true,
},
someothertype: {
type: 'someothertype',
hasId: true,
collection_type: 'coll-sometype',
},
'coll-edbfunc': {
type: 'coll-edbfunc',
hasId: true,
label: 'Functions',
},
'coll-edbproc': {
type: 'coll-edbfunc',
hasId: true,
label: 'Procedures',
},
'coll-edbvar': {
type: 'coll-edbfunc',
hasId: true,
label: 'Variables',
},
},
keyboardNavigation: jasmine.createSpyObj('keyboardNavigation', ['getDialogTabNavigator']),
};
noDataNode = pgBrowser.treeMenu.addNewNode('level1.1', undefined, [{id: 'level1'}]);
serverTreeNode = pgBrowser.treeMenu.addNewNode('level2.1', {
_type: 'server',
_id: 10,
label: 'some-tree-label',
}, [{id: 'level2.1'}]);
databaseTreeNode = new TreeNode('database-tree-node', {
_type: 'database',
_id: 123,
_label: 'some-database-label',
}, [{id: 'database-tree-node'}]);
pgBrowser.treeMenu.addChild(serverTreeNode, databaseTreeNode);
jquerySpy = jasmine.createSpy('jquerySpy');
soNode = {
__internal: {
buttons: [{}, {}, {}, {
element: {
disabled: false,
},
}],
},
elements: {
body: {
childNodes: [
{},
],
},
content: jasmine.createSpyObj('content', ['appendChild', 'attr']),
},
};
soJQueryContainerSpy = jasmine.createSpyObj('soJQueryContainer', ['get', 'attr']);
soJQueryContainerSpy.get.and.returnValue(soJQueryContainerSpy);
viewSchema = {};
backform = jasmine.createSpyObj('backform', ['generateViewSchema', 'Dialog']);
backform.generateViewSchema.and.returnValue(viewSchema);
soNodeChildNodeSpy = jasmine.createSpyObj('something', ['addClass']);
jquerySpy.and.callFake((selector) => {
if (selector === '<div class=\'search_objects_dialog\'></div>') {
return soJQueryContainerSpy;
} else if (selector === soNode.elements.body.childNodes[0]) {
return soNodeChildNodeSpy;
}
});
alertifySpy = jasmine.createSpyObj('alertify', ['alert', 'dialog']);
});
describe('#prepare', () => {
beforeEach(() => {
soDialogWrapper = new SearchObjectsDialogWrapper(
'<div class=\'search_objects_dialog\'></div>',
'soDialogTitle',
'search_objects',
jquerySpy,
pgBrowser,
alertifySpy,
dialogModelKlassSpy,
backform
);
soDialogWrapper = Object.assign(soDialogWrapper, soNode);
spyOn(soDialogWrapper, 'prepareDialog').and.callThrough();
spyOn(soDialogWrapper, 'setTypes');
spyOn(soDialogWrapper, 'setResultCount');
});
context('no tree element is selected', () => {
it('does not prepare dialog', () => {
spyOn(soDialogWrapper, 'prepareDialog');
soDialogWrapper.prepare();
expect(soDialogWrapper.prepareDialog).not.toHaveBeenCalled();
});
});
context('selected tree node has no data', () => {
beforeEach(() => {
pgBrowser.treeMenu.selectNode(noDataNode.domNode);
});
it('does not prepare the dialog', () => {
spyOn(soDialogWrapper, 'prepareDialog');
soDialogWrapper.prepare();
expect(soDialogWrapper.prepareDialog).not.toHaveBeenCalled();
});
});
context('tree element is selected', () => {
let gridDestroySpy;
let networkMock;
beforeEach(() => {
pgBrowser.treeMenu.selectNode(databaseTreeNode.domNode);
soDialogWrapper.grid = jasmine.createSpyObj('grid', ['destroy']);
spyOn(soDialogWrapper, 'showMessage');
gridDestroySpy = spyOn(soDialogWrapper.grid, 'destroy');
networkMock = new MockAdapter(axios);
});
afterEach(() => {
networkMock.restore();
});
it('creates dialog and displays it', () => {
soDialogWrapper.prepare();
expect(soDialogWrapper.prepareDialog).toHaveBeenCalled();
expect(soDialogWrapper.showMessage).toHaveBeenCalledWith(null);
});
it('if grid set then destroy it', () => {
soDialogWrapper.prepare();
expect(gridDestroySpy).toHaveBeenCalled();
expect(soDialogWrapper.grid).toBe(null);
});
it('set result count to 0', () => {
soDialogWrapper.prepare();
expect(soDialogWrapper.setResultCount).toHaveBeenCalledWith(0);
});
it('setTypes called before and after the ajax success', (done) => {
networkMock.onGet('/search_objects/types/10/123').reply(200, {
'data': {
'type1': 'Type Label 1',
'type2': 'Type Label 2',
},
});
soDialogWrapper.prepare();
expect(soDialogWrapper.setTypes.calls.argsFor(0)).toEqual([
[{ id: -1, text: 'Loading...', value: null }], false,
]);
setTimeout(()=>{
expect(soDialogWrapper.setTypes.calls.argsFor(1)).toEqual([
[{id: 'all', text: 'All types'},
{id: 'type1', text: 'Type Label 1'},
{id: 'type2', text: 'Type Label 2'}],
]);
done();
}, 0);
});
it('setTypes called after the ajax fail', (done) => {
networkMock.onGet('/search_objects/types/10/123').reply(500);
soDialogWrapper.prepare();
expect(soDialogWrapper.setTypes.calls.argsFor(0)).toEqual([
[{ id: -1, text: 'Loading...', value: null }], false,
]);
setTimeout(()=>{
expect(soDialogWrapper.setTypes.calls.argsFor(1)).toEqual([
[{id: -1, text: 'Failed', value: null }], false,
]);
done();
}, 0);
});
});
});
describe('showMessage', () => {
beforeEach(() => {
soDialogWrapper = new SearchObjectsDialogWrapper(
'<div class=\'search_objects_dialog\'></div>',
'soDialogTitle',
'search_objects',
jquerySpy,
pgBrowser,
alertifySpy,
dialogModelKlassSpy,
backform
);
soDialogWrapper.statusBar = document.createElement('div');
soDialogWrapper.statusBar.classList.add('d-none');
document.body.appendChild(soDialogWrapper.statusBar);
});
afterEach(() => {
document.body.removeChild(soDialogWrapper.statusBar);
});
it('when info message', ()=>{
soDialogWrapper.showMessage('locating', false);
expect(soDialogWrapper.statusBar.classList.contains('d-none')).toBe(false);
expect(soDialogWrapper.statusBar.querySelector('.error-in-footer')).toBe(null);
expect(soDialogWrapper.statusBar.querySelector('.info-in-footer')).not.toBe(null);
expect(soDialogWrapper.statusBar.querySelector('.alert-text').innerHTML).toEqual('locating');
});
it('when error message', ()=>{
soDialogWrapper.showMessage('some error', true);
expect(soDialogWrapper.statusBar.classList.contains('d-none')).toBe(false);
expect(soDialogWrapper.statusBar.querySelector('.error-in-footer')).not.toBe(null);
expect(soDialogWrapper.statusBar.querySelector('.info-in-footer')).toBe(null);
expect(soDialogWrapper.statusBar.querySelector('.alert-text').innerHTML).toEqual('some error');
});
it('when no message', ()=>{
soDialogWrapper.showMessage(null);
expect(soDialogWrapper.statusBar.classList.contains('d-none')).toBe(true);
});
});
describe('function', () => {
beforeEach(() => {
soDialogWrapper = new SearchObjectsDialogWrapper(
'<div class=\'search_objects_dialog\'></div>',
'soDialogTitle',
'search_objects',
jquerySpy,
pgBrowser,
alertifySpy,
dialogModelKlassSpy,
backform
);
});
it('updateDimOfSearchResult', ()=>{
soDialogWrapper.searchResultContainer = document.createElement('div');
soDialogWrapper.searchResult = document.createElement('div');
spyOn(soDialogWrapper.searchResultContainer, 'getBoundingClientRect').and.returnValue({height:100, width: 50});
soDialogWrapper.updateDimOfSearchResult();
expect(soDialogWrapper.searchResult.style.height).toEqual('100px');
expect(soDialogWrapper.searchResult.style.width).toEqual('50px');
});
it('setLoading', ()=>{
soDialogWrapper.loader = document.createElement('div');
soDialogWrapper.loader.innerHTML = `
<div class="pg-sp-text"></div>
`;
soDialogWrapper.setLoading('loading');
expect(soDialogWrapper.loader.classList.contains('d-none')).toBe(false);
expect(soDialogWrapper.loader.querySelector('.pg-sp-text').innerHTML).toEqual('loading');
soDialogWrapper.setLoading(null);
expect(soDialogWrapper.loader.classList.contains('d-none')).toBe(true);
});
it('searchBtnEnabled', ()=>{
soDialogWrapper.searchBtn = document.createElement('button');
soDialogWrapper.searchBtnEnabled(true);
expect(soDialogWrapper.searchBtn.disabled).toEqual(false);
expect(soDialogWrapper.searchBtnEnabled()).toEqual(true);
soDialogWrapper.searchBtnEnabled(false);
expect(soDialogWrapper.searchBtn.disabled).toEqual(true);
expect(soDialogWrapper.searchBtnEnabled()).toEqual(false);
});
it('searchBoxVal', ()=>{
soDialogWrapper.searchBox = document.createElement('input');
soDialogWrapper.searchBoxVal('abc');
expect(soDialogWrapper.searchBox.value).toEqual('abc');
expect(soDialogWrapper.searchBoxVal()).toEqual('abc');
});
it('typesVal', ()=>{
soDialogWrapper.typesSelect = document.createElement('select');
let opt = document.createElement('option');
opt.appendChild( document.createTextNode('Some type') );
opt.value = 'sometype';
soDialogWrapper.typesSelect.appendChild(opt);
soDialogWrapper.typesVal('sometype');
expect(soDialogWrapper.typesSelect.value).toEqual('sometype');
expect(soDialogWrapper.typesVal()).toEqual('sometype');
});
it('setGridData', ()=>{
soDialogWrapper.dataview = jasmine.createSpyObj('dataview', ['setItems']);
soDialogWrapper.setGridData([{id:'somedata'}]);
expect(soDialogWrapper.dataview.setItems).toHaveBeenCalled();
});
it('setGridData', ()=>{
soDialogWrapper.searchResultCount = document.createElement('span');
soDialogWrapper.setResultCount(0);
expect(soDialogWrapper.searchResultCount.innerHTML).toEqual('0 matches found.');
soDialogWrapper.setResultCount(1);
expect(soDialogWrapper.searchResultCount.innerHTML).toEqual('1 match found.');
soDialogWrapper.setResultCount();
expect(soDialogWrapper.searchResultCount.innerHTML).toEqual('Unknown matches found.');
});
it('onDialogResize', ()=>{
soDialogWrapper.grid = jasmine.createSpyObj('grid', ['autosizeColumns', 'resizeCanvas']);
spyOn(soDialogWrapper, 'updateDimOfSearchResult');
soDialogWrapper.onDialogResize();
expect(soDialogWrapper.updateDimOfSearchResult).toHaveBeenCalled();
expect(soDialogWrapper.grid.resizeCanvas).toHaveBeenCalled();
expect(soDialogWrapper.grid.autosizeColumns).toHaveBeenCalled();
});
it('onDialogShow', (done)=>{
spyOn(soDialogWrapper, 'prepareGrid').and.callFake(function() {
this.grid = jasmine.createSpyObj('grid', ['init']);
});
spyOn(soDialogWrapper, 'focusOnDialog');
spyOn(soDialogWrapper, 'updateDimOfSearchResult');
spyOn(soDialogWrapper, 'setGridData');
spyOn(soDialogWrapper, 'onDialogResize');
soDialogWrapper.onDialogShow();
setTimeout(()=>{
expect(soDialogWrapper.prepareGrid).toHaveBeenCalled();
expect(soDialogWrapper.focusOnDialog).toHaveBeenCalled();
expect(soDialogWrapper.setGridData).toHaveBeenCalledWith([]);
expect(soDialogWrapper.onDialogResize).toHaveBeenCalled();
done();
}, 750);
});
context('getCollNode', ()=>{
it('type have same coll node', ()=>{
let collNode = soDialogWrapper.getCollNode('sometype');
expect(collNode.type).toEqual('coll-sometype');
});
it('type does not same coll node', ()=>{
let collNode = soDialogWrapper.getCollNode('someothertype');
expect(collNode.type).toEqual('coll-sometype');
});
it('type does not have coll node at all', ()=>{
let collNode = soDialogWrapper.getCollNode('database');
expect(collNode).toBe(null);
});
});
it('finaliseData', ()=>{
spyOn(soDialogWrapper, 'translateSearchObjectsPath').and.returnValue(['disp/path', 'id/path']);
let data = soDialogWrapper.finaliseData({
name: 'objname',
type: 'sometype',
type_label: 'Some types coll',
path: ':some.123:/path',
show_node: true,
});
expect(data).toEqual({
id: 'id/path',
icon: 'icon-sometype',
name: 'objname',
type: 'sometype',
type_label: 'Some types coll',
path: 'disp/path',
id_path: 'id/path',
show_node: true,
});
});
context('translateSearchObjectsPath', ()=>{
let path = null, catalog_level = null;
beforeEach(()=>{
pgBrowser.Nodes = {
'server_group': {
type:'server_group',
label: 'Server group',
},
'server': {
type:'server',
label: 'Server',
},
'coll-database': {
type:'coll-database',
label: 'Databases',
},
'database': {
type:'database',
label: 'Database',
},
'coll-schema': {
type:'coll-schema',
label: 'Schemas',
},
'schema': {
type:'schema',
label: 'Schema',
},
'coll-table': {
type:'coll-table',
label: 'Tables',
},
'table': {
type:'table',
label: 'Table',
},
'sometype': {
type:'sometype',
label: 'Some type',
collection_type: 'coll-table',
},
'coll-catalog': {
type:'coll-catalog',
label: 'Catalogs',
},
'catalog': {
type:'catalog',
label: 'Catalog',
},
'coll-catalog_object': {
type:'coll-catalog_object',
label: 'Catalog Objects',
},
'catalog_object': {
type:'catalog_object',
label: 'catalog object',
},
};
soDialogWrapper.treeInfo = {
'server_group': {'id': 'server_group/1', '_id': 1},
'server': {'id': 'server/3', '_id': 3},
'database': {'id': 'database/18456', '_id': 18456},
};
});
it('regular schema', ()=>{
path = ':schema.2200:/test_db/:table.2604:/sampletab';
catalog_level = 'N';
let retVal = soDialogWrapper.translateSearchObjectsPath(path, catalog_level);
expect(retVal).toEqual([
'Schemas/test_db/Tables/sampletab',
['server_group/1','server/3','coll-database/3','database/18456','coll-schema/18456','schema/2200','coll-table/2200','table/2604'],
]);
});
context('catalog schema', ()=>{
it('with db support', ()=>{
path = ':schema.11:/PostgreSQL Catalog (pg_catalog)/:table.2604:/pg_class';
catalog_level = 'D';
let retVal = soDialogWrapper.translateSearchObjectsPath(path, catalog_level);
expect(retVal).toEqual([
'Catalogs/PostgreSQL Catalog (pg_catalog)/Tables/pg_class',
['server_group/1','server/3','coll-database/3','database/18456','coll-catalog/18456','catalog/11','coll-table/11','table/2604'],
]);
});
it('with object support only', ()=>{
path = ':schema.11:/ANSI (information_schema)/:table.2604:/attributes';
catalog_level = 'O';
let retVal = soDialogWrapper.translateSearchObjectsPath(path, catalog_level);
expect(retVal).toEqual([
'Catalogs/ANSI (information_schema)/Catalog Objects/attributes',
['server_group/1','server/3','coll-database/3','database/18456','coll-catalog/18456','catalog/11','coll-catalog_object/11','catalog_object/2604'],
]);
});
});
});
});
});

View File

@@ -41,6 +41,9 @@ export class TreeFake extends Tree {
this.aciTreeToOurTreeTranslator = {};
this.aciTreeApi = jasmine.createSpyObj(
'ACITreeApi', ['setInode', 'unload', 'deselect', 'select']);
this.aciTreeApi.unload.and.callFake(function(domNode, config) {
config.success();
});
}
addNewNode(id, data, domNode, path) {

View File

@@ -246,39 +246,70 @@ describe('tree tests', () => {
tree.aciTreeApi = jasmine.createSpyObj(
'ACITreeApi', ['setInode', 'unload', 'deselect', 'select']);
tree.aciTreeApi.unload.and.callFake((domNode, config) => {
config.success();
});
});
it('reloads the node and its children', () => {
level2.reload(tree);
expect(tree.findNodeByDomElement([{id: 'level2'}])).toEqual(level2);
it('reloads the node and its children', (done) => {
level2.reload(tree)
.then(()=>{
expect(tree.findNodeByDomElement([{id: 'level2'}])).toEqual(level2);
done();
})
.catch((error)=>{
fail(error);
});
});
it('does not reload the children of node', () => {
level2.reload(tree);
expect(tree.findNodeByDomElement([{id: 'level3'}])).toBeNull();
it('does not reload the children of node', (done) => {
level2.reload(tree)
.then(()=>{
expect(tree.findNodeByDomElement([{id: 'level3'}])).toBeNull();
done();
})
.catch((error)=>{
fail(error);
});
});
it('select the node', (done) => {
level2.reload(tree);
setTimeout(() => {
expect(tree.selected()).toEqual([{id: 'level2'}]);
done();
}, 20);
level2.reload(tree)
.then(()=>{
setTimeout(() => {
expect(tree.selected()).toEqual([{id: 'level2'}]);
done();
}, 20);
})
.catch((error)=>{
fail(error);
});
});
describe('ACITree specific', () => {
it('sets the current node as a Inode, changing the Icon back to +', () => {
level2.reload(tree);
expect(tree.aciTreeApi.setInode).toHaveBeenCalledWith([{id: 'level2'}]);
it('sets the current node as a Inode, changing the Icon back to +', (done) => {
level2.reload(tree)
.then(()=>{
expect(tree.aciTreeApi.setInode).toHaveBeenCalledWith([{id: 'level2'}]);
done();
})
.catch((error)=>{
fail(error);
});
});
it('deselect the node and selects it again to trigger ACI tree' +
' events', (done) => {
level2.reload(tree);
setTimeout(() => {
expect(tree.aciTreeApi.deselect).toHaveBeenCalledWith([{id: 'level2'}]);
done();
}, 20);
level2.reload(tree)
.then(()=>{
setTimeout(() => {
expect(tree.aciTreeApi.deselect).toHaveBeenCalledWith([{id: 'level2'}]);
done();
}, 20);
})
.catch((error)=>{
fail(error);
});
});
});
});
@@ -292,17 +323,32 @@ describe('tree tests', () => {
level2 = tree.addNewNode('level2', {data: 'data'}, ['<li>level2</li>'], ['level1']);
tree.addNewNode('level3', {data: 'more data'}, ['<li>level3</li>'], ['level1', 'level2']);
tree.aciTreeApi = jasmine.createSpyObj('ACITreeApi', ['unload']);
tree.aciTreeApi.unload.and.callFake((domNode, config) => {
config.success();
});
});
it('unloads the children of the current node', () => {
level2.unload(tree);
expect(tree.findNodeByDomElement([{id: 'level2'}])).toEqual(level2);
expect(tree.findNodeByDomElement([{id: 'level3'}])).toBeNull();
it('unloads the children of the current node', (done) => {
level2.unload(tree)
.then(()=>{
expect(tree.findNodeByDomElement([{id: 'level2'}])).toEqual(level2);
expect(tree.findNodeByDomElement([{id: 'level3'}])).toBeNull();
done();
})
.catch((error)=>{
fail(error);
});
});
it('calls unload on the ACI Tree', () => {
level2.unload(tree);
expect(tree.aciTreeApi.unload).toHaveBeenCalledWith(['<li>level2</li>']);
it('calls unload on the ACI Tree', (done) => {
level2.unload(tree)
.then(()=>{
expect(tree.aciTreeApi.unload).toHaveBeenCalledWith(['<li>level2</li>'], jasmine.any(Object));
done();
})
.catch((error)=>{
fail(error);
});
});
});
});

View File

@@ -494,7 +494,8 @@ module.exports = [{
',pgadmin.tools.debugger.controller' +
',pgadmin.tools.debugger.direct' +
',pgadmin.node.pga_job' +
',pgadmin.tools.schema_diff',
',pgadmin.tools.schema_diff' +
',pgadmin.tools.search_objects',
},
}, {
test: require.resolve('snapsvg'),

View File

@@ -277,6 +277,8 @@ var webpackShimConfig = {
'pgadmin.tools.restore': path.join(__dirname, './pgadmin/tools/restore/static/js/restore'),
'pgadmin.tools.schema_diff': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff'),
'pgadmin.tools.schema_diff_ui': path.join(__dirname, './pgadmin/tools/schema_diff/static/js/schema_diff_ui'),
'pgadmin.tools.search_objects': path.join(__dirname, './pgadmin/tools/search_objects/static/js/search_objects'),
'pgadmin.search_objects': path.join(__dirname, './pgadmin/tools/search_objects/static/js'),
'pgadmin.tools.user_management': path.join(__dirname, './pgadmin/tools/user_management/static/js/user_management'),
'pgadmin.user_management.current_user': '/user_management/current_user',
'slick.pgadmin.editors': path.join(__dirname, './pgadmin/tools/../static/js/slickgrid/editors'),

View File

@@ -105,6 +105,7 @@ module.exports = {
'pgadmin.browser.preferences': path.join(__dirname, './pgadmin/browser/static/js/preferences'),
'pgadmin.browser.activity': path.join(__dirname, './pgadmin/browser/static/js/activity'),
'bundled_codemirror': path.join(__dirname, './pgadmin/static/bundle/codemirror'),
'tools': path.join(__dirname, './pgadmin/tools/'),
},
},
};

File diff suppressed because it is too large Load Diff