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

@@ -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