diff --git a/web/config.py b/web/config.py index f4609e4e..90dd4ded 100644 --- a/web/config.py +++ b/web/config.py @@ -299,7 +299,8 @@ STORAGE_DIR = os.path.join(DATA_DIR, 'storage') ########################################################################## DEFAULT_BINARY_PATHS = { "pg": "", - "ppas": "" + "ppas": "", + "gpdb": "" } ########################################################################## diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/create.sql new file mode 100644 index 00000000..9bcfd598 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/create.sql @@ -0,0 +1,168 @@ +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{% import 'macros/variable.macros' as VARIABLE %} +{% import 'column/macros/security.macros' as COLUMN_SECLABEL %} +{% import 'column/macros/privilege.macros' as COLUMN_PRIVILEGE %} +{% import 'table/sql/macros/constraints.macro' as CONSTRAINTS %} +{% import 'type/macros/get_full_type_sql_format.macros' as GET_TYPE %} +{#===========================================#} +{#====== MAIN TABLE TEMPLATE STARTS HERE ======#} +{#===========================================#} +{# + If user has not provided any details but only name then + add empty bracket with table name +#} +{% set empty_bracket = ""%} +{% if data.coll_inherits|length == 0 and data.columns|length == 0 and not data.typname and not data.like_relation and data.primary_key|length == 0 and data.unique_constraint|length == 0 and data.foreign_key|length == 0 and data.check_constraint|length == 0 and data.exclude_constraint|length == 0 %} +{% set empty_bracket = "\n(\n)"%} +{% endif %} +CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{{empty_bracket}} +{% if data.typname %} + OF {{ data.typname }} +{% endif %} +{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %} +( +{% endif %} +{% if data.like_relation %} + LIKE {{ data.like_relation }}{% if data.like_default_value %} + + INCLUDING DEFAULTS{% endif %}{% if data.like_constraints %} + + INCLUDING CONSTRAINTS{% endif %}{% if data.like_indexes %} + + INCLUDING INDEXES{% endif %}{% if data.like_storage %} + + INCLUDING STORAGE{% endif %}{% if data.like_comments %} + + INCLUDING COMMENTS{% endif %}{% if data.columns|length > 0 %}, +{% endif %} + +{% endif %} +{### Add columns ###} +{% if data.columns and data.columns|length > 0 %} +{% for c in data.columns %} +{% if c.name and c.cltype %} +{% if loop.index != 1 %}, +{% endif %} + {{conn|qtIdent(c.name)}} {% if is_sql %}{{c.displaytypname}}{% else %}{{ GET_TYPE.CREATE_TYPE_SQL(conn, c.cltype, c.attlen, c.attprecision, c.hasSqrBracket) }}{% endif %}{% if c.collspcname %} COLLATE {{c.collspcname}}{% endif %}{% if c.attnotnull %} NOT NULL{% endif %}{% if c.defval %} DEFAULT {{c.defval}}{% endif %} +{% endif %} +{% endfor %} +{% endif %} +{# Macro to render for constraints #} +{% if data.primary_key|length > 0 %}{% if data.columns|length > 0 %},{% endif %} +{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 %},{% endif %} +{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 %},{% endif %} +{{CONSTRAINTS.FOREIGN_KEY(conn, data.foreign_key)}}{% endif %}{% if data.check_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 %},{% endif %} +{{CONSTRAINTS.CHECK(conn, data.check_constraint)}}{% endif %}{% if data.exclude_constraint|length > 0 %}{% if data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 %},{% endif %} +{{CONSTRAINTS.EXCLUDE(conn, data.exclude_constraint)}}{% endif %} +{% if data.like_relation or data.coll_inherits or data.columns|length > 0 or data.primary_key|length > 0 or data.unique_constraint|length > 0 or data.foreign_key|length > 0 or data.check_constraint|length > 0 or data.exclude_constraint|length > 0 %} + +){% endif %}{% if data.relkind is defined and data.relkind == 'p' %} PARTITION BY {{ data.partition_scheme }} {% endif %} + +{### If we are inheriting it from another table(s) ###} +{% if data.coll_inherits %} + INHERITS ({% for val in data.coll_inherits %}{% if loop.index != 1 %}, {% endif %}{{val}}{% endfor %}) +{% endif %} +WITH ( + OIDS = {% if data.relhasoids %}TRUE{% else %}FALSE{% endif %}{% if data.fillfactor %}, + FILLFACTOR = {{ data.fillfactor }}{% endif %}{% if data.appendonly %}, + APPENDONLY = TRUE{% endif %}{% if data.compresslevel %}, + COMPRESSLEVEL = {{ data.compresslevel }}{% endif %}{% if data.blocksize %}, + BLOCKSIZE = {{ data.blocksize }}{% endif %}{% if data.orientation %}, + ORIENTATION = {{ data.orientation.upper() }}{% endif %}{% if data.compresstype %}, + COMPRESSTYPE = {{ data.compresstype.upper() }}{% endif %}{% if data.autovacuum_custom %}, + autovacuum_enabled = {% if data.autovacuum_enabled %}TRUE{% else %}FALSE{% endif %}{% endif %}{% if data.toast_autovacuum %}, + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled %}TRUE{% else %}FALSE{% endif %} +{% endif %}{% if data.autovacuum_enabled and data.vacuum_table|length > 0 %} + +{% for opt in data.vacuum_table %}{% if opt.name and opt.value %} +, + {{opt.name}} = {{opt.value}}{% endif %} +{% endfor %}{% endif %}{% if data.toast_autovacuum_enabled and data.vacuum_toast|length > 0 %} +{% for opt in data.vacuum_toast %}{% if opt.name and opt.value %} +, + toast.{{opt.name}} = {{opt.value}}{% endif %} +{% endfor %}{% endif %} + +) +{### SQL for Tablespace ###} +{% if data.spcname %} +TABLESPACE {{ conn|qtIdent(data.spcname) }} +{% endif %} +{### SQL for Distribution ###} +{% if data.distribution %} +DISTRIBUTED BY ({% for attrnum in data.distribution %}{% if loop.index != 1 %}, {% endif %}{{ data.columns[attrnum-1].name }}{% endfor %}); +{% else %} +DISTRIBUTED RANDOMLY; +{% endif %} + +{### Alter SQL for Owner ###} +{% if data.relowner %} + +ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} + OWNER to {{conn|qtIdent(data.relowner)}}; +{% endif %} +{### Security Labels on Table ###} +{% if data.seclabels and data.seclabels|length > 0 %} + +{% for r in data.seclabels %} +{{ SECLABEL.SET(conn, 'TABLE', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{### ACL on Table ###} +{% if data.relacl %} +{% for priv in data.relacl %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{### SQL for COMMENT ###} +{% if data.description %} +COMMENT ON TABLE {{conn|qtIdent(data.schema, data.name)}} + IS {{data.description|qtLiteral}}; +{% endif %} +{#===========================================#} +{#====== MAIN TABLE TEMPLATE ENDS HERE ======#} +{#===========================================#} +{#===========================================#} +{# COLUMN SPECIFIC TEMPLATES STARTS HERE #} +{#===========================================#} +{% if data.columns and data.columns|length > 0 %} +{% for c in data.columns %} +{% if c.description %} + +COMMENT ON COLUMN {{conn|qtIdent(data.schema, data.name, c.name)}} + IS {{c.description|qtLiteral}}; +{% endif %} +{### Add variables to column ###} +{% if c.attoptions and c.attoptions|length > 0 %} + +ALTER TABLE {{conn|qtIdent(data.schema, data.name)}} + {{ VARIABLE.SET(conn, 'COLUMN', c.name, c.attoptions) }} +{% endif %} +{### ACL ###} +{% if c.attacl and c.attacl|length > 0 %} + +{% for priv in c.attacl %} + {{ COLUMN_PRIVILEGE.APPLY(conn, data.schema, data.name, c.name, priv.grantee, priv.without_grant, priv.with_grant) }} +{% endfor %} +{% endif %} +{### Security Lables ###} +{% if c.seclabels and c.seclabels|length > 0 %} + +{% for r in c.seclabels %} +{{ COLUMN_SECLABEL.APPLY(conn, 'COLUMN',data.schema, data.name, c.name, r.provider, r.label) }} +{% endfor %} +{% endif %} +{% endfor %} +{% endif %} +{#===========================================#} +{# COLUMN SPECIFIC TEMPLATES ENDS HERE #} +{#===========================================#} +{#======================================#} +{# CONSTRAINTS SPECIFIC TEMPLATES #} +{#======================================#} +{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.primary_key)}} +{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.unique_constraint)}} +{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.foreign_key)}} +{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.check_constraint)}} +{{CONSTRAINTS.CONSTRAINT_COMMENTS(conn, data.schema, data.name, data.exclude_constraint)}} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/properties.sql new file mode 100644 index 00000000..83176a45 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/gpdb_5.0_plus/properties.sql @@ -0,0 +1,82 @@ +SELECT *, + (CASE when pre_coll_inherits is NULL then ARRAY[]::varchar[] else pre_coll_inherits END) as coll_inherits +FROM ( + SELECT rel.oid, rel.relname AS name, rel.reltablespace AS spcoid,rel.relacl AS relacl_str, + (CASE WHEN length(spc.spcname) > 0 THEN spc.spcname ELSE + (SELECT sp.spcname FROM pg_database dtb + JOIN pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END) as spcname, + (select nspname FROM pg_namespace WHERE oid = {{scid}}::oid ) as schema, + pg_get_userbyid(rel.relowner) AS relowner, rel.relhasoids, + rel.relhassubclass, rel.reltuples, des.description, con.conname, con.conkey, + EXISTS(select 1 FROM pg_trigger + JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger' + JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion' + WHERE tgrelid=rel.oid) AS isrepl, + (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid) AS triggercount, + (SELECT ARRAY(SELECT CASE WHEN (nspname NOT LIKE E'pg\_%') THEN + quote_ident(nspname)||'.'||quote_ident(c.relname) + ELSE quote_ident(c.relname) END AS inherited_tables + FROM pg_inherits i + JOIN pg_class c ON c.oid = i.inhparent + JOIN pg_namespace n ON n.oid=c.relnamespace + WHERE i.inhrelid = rel.oid ORDER BY inhseqno)) AS pre_coll_inherits, + (SELECT count(*) + FROM pg_inherits i + JOIN pg_class c ON c.oid = i.inhparent + JOIN pg_namespace n ON n.oid=c.relnamespace + WHERE i.inhrelid = rel.oid) AS inherited_tables_cnt, + false AS relpersistence, + substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor, + substring(array_to_string(rel.reloptions, ',') FROM 'compresslevel=([0-9]*)') AS compresslevel, + substring(array_to_string(rel.reloptions, ',') FROM 'blocksize=([0-9]*)') AS blocksize, + substring(array_to_string(rel.reloptions, ',') FROM 'orientation=(row|column)') AS orientation, + substring(array_to_string(rel.reloptions, ',') FROM 'appendonly=(true|false)')::boolean AS appendonly, + substring(array_to_string(rel.reloptions, ',') FROM 'compresstype=(zlib|quicklz|rle_type|none)') AS compresstype, + (CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') + THEN true ELSE false END) AS autovacuum_enabled, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS autovacuum_analyze_scale_factor, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)') = 'true') + THEN true ELSE false END) AS toast_autovacuum_enabled, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_analyze_scale_factor=([0-9]*[.][0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + array_to_string(rel.reloptions, ',') AS table_vacuum_settings_str, + array_to_string(tst.reloptions, ',') AS toast_table_vacuum_settings_str, + rel.reloptions AS reloptions, tst.reloptions AS toast_reloptions, NULL AS reloftype, NULL AS typname, + (CASE WHEN rel.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable, + -- Added for pgAdmin4 + (CASE WHEN (substring(array_to_string(rel.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean THEN true ELSE false END) AS autovacuum_custom, + (CASE WHEN (substring(array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::boolean AND rel.reltoastrelid != 0 THEN true ELSE false END) AS toast_autovacuum, + + ARRAY[]::varchar[] AS seclabels, + (CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table, + + gdp.attrnums AS distribution + + FROM pg_class rel + LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace + LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0 AND des.classoid='pg_class'::regclass) + LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p' + LEFT OUTER JOIN pg_class tst ON tst.oid = rel.reltoastrelid + LEFT OUTER JOIN gp_distribution_policy gdp ON gdp.localoid = rel.oid + + WHERE rel.relkind IN ('r','s','t') AND rel.relnamespace = {{ scid }} + {% if tid %} AND rel.oid = {{ tid }}::oid {% endif %} +) AS TableInformation + ORDER BY name diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py index 1ac35054..a469f2ea 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py @@ -104,8 +104,13 @@ class BaseTableView(PGChildNodeView): did in self.manager.db_info else 0 ver = self.manager.version + server_type = self.manager.server_type # Set the template path for the SQL scripts - self.table_template_path = 'table/sql/#{0}#'.format(ver) + self.table_template_path = 'table/sql/' + ( + '#{0}#{1}#'.format(server_type, ver) + if server_type == 'gpdb' else + '#{0}#'.format(ver) + ) self.partition_template_path = 'partition/sql/#{0}#'.format(ver) # Template for Column ,check constraint and exclusion diff --git a/web/pgadmin/browser/server_groups/servers/gpdb.py b/web/pgadmin/browser/server_groups/servers/gpdb.py new file mode 100644 index 00000000..878063d2 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/gpdb.py @@ -0,0 +1,20 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2017, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +from flask_babel import gettext +from pgadmin.browser.server_groups.servers.types import ServerType + + +class GPDB(ServerType): + def instanceOf(self, ver): + return "Greenplum Database" in ver + + +# Default Server Type +GPDB('gpdb', gettext("Greenplum Database"), 3) diff --git a/web/pgadmin/dashboard/__init__.py b/web/pgadmin/dashboard/__init__.py index 8ebab16c..a41492f4 100644 --- a/web/pgadmin/dashboard/__init__.py +++ b/web/pgadmin/dashboard/__init__.py @@ -218,7 +218,12 @@ def check_precondition(f): g.server_type = g.manager.server_type g.version = g.manager.version - g.template_path = 'dashboard/sql/#{0}#'.format(g.version) + # Include server_type in template_path when server_type is gpdb + g.template_path = 'dashboard/sql/' + ( + '#{0}#{1}#'.format(g.server_type, g.version) + if g.server_type == 'gpdb' else + '#{0}#'.format(g.version) + ) return f(*args, **kwargs) diff --git a/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/activity.sql b/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/activity.sql new file mode 100644 index 00000000..1a0a0243 --- /dev/null +++ b/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/activity.sql @@ -0,0 +1,14 @@ +SELECT + procpid AS pid, + datname, + usename, + application_name, + client_addr, + to_char(backend_start, 'YYYY-MM-DD HH24:MI:SS TZ') AS backend_start, + CASE WHEN current_query LIKE '%' THEN 'idle' ELSE 'active' END AS state, + CASE WHEN waiting THEN '{{ _('yes') }}' ELSE '{{ _('no') }}' END AS waiting +FROM + pg_stat_activity +{% if did %}WHERE + datid = {{ did }} {% endif %} +ORDER BY pid diff --git a/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/locks.sql b/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/locks.sql new file mode 100644 index 00000000..511838d7 --- /dev/null +++ b/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/locks.sql @@ -0,0 +1,22 @@ +SELECT + pid, + locktype, + datname, + relation::regclass, + page, + tuple, + virtualxid + transactionid, + classid::regclass, + objid, + objsubid, + virtualtransaction, + mode, + granted +FROM + pg_locks l + LEFT OUTER JOIN pg_database d ON (l.database = d.oid) +{% if did %}WHERE + database = {{ did }}{% endif %} +ORDER BY + pid, locktype diff --git a/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/session_stats.sql b/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/session_stats.sql new file mode 100644 index 00000000..533c445b --- /dev/null +++ b/web/pgadmin/dashboard/templates/dashboard/sql/gpdb_5.0_plus/session_stats.sql @@ -0,0 +1,4 @@ +SELECT + (SELECT count(*) FROM pg_stat_activity{% if did %} WHERE datid = {{ did }} {% endif %}) AS "{{ _('Total') }}", + (SELECT count(*) FROM pg_stat_activity WHERE current_query NOT LIKE '%'{% if did %} AND datid = {{ did }} {% endif %}) AS "{{ _('Active') }}", + (SELECT count(*) FROM pg_stat_activity WHERE current_query LIKE '%'{% if did %} AND datid = {{ did }} {% endif %}) AS "{{ _('Idle') }}" diff --git a/web/pgadmin/utils/tests/templates/some_feature/sql/gpdb_5.0_plus/some_action_with_gpdb_5_0.sql b/web/pgadmin/utils/tests/templates/some_feature/sql/gpdb_5.0_plus/some_action_with_gpdb_5_0.sql new file mode 100644 index 00000000..e131e3fd --- /dev/null +++ b/web/pgadmin/utils/tests/templates/some_feature/sql/gpdb_5.0_plus/some_action_with_gpdb_5_0.sql @@ -0,0 +1 @@ +Some default SQL for GPDB diff --git a/web/pgadmin/utils/tests/test_versioned_template_loader.py b/web/pgadmin/utils/tests/test_versioned_template_loader.py index a0d97899..9f3bd07f 100644 --- a/web/pgadmin/utils/tests/test_versioned_template_loader.py +++ b/web/pgadmin/utils/tests/test_versioned_template_loader.py @@ -23,7 +23,10 @@ class TestVersionedTemplateLoader(BaseTestGenerator): ("Render a version 9.1 template when it is present", dict(scenario=2)), ("Render a version 9.2 template when request for a higher version", dict(scenario=3)), ("Render default version when version 9.0 was requested and only 9.1 and 9.2 are present", dict(scenario=4)), - ("Raise error when version is smaller than available templates", dict(scenario=5)) + ("Raise error when version is smaller than available templates", dict(scenario=5)), + ("Render a version GPDB 5.0 template when it is present", dict(scenario=6)), + ("Render a version GPDB 5.0 template when it is in default", dict(scenario=7)), + ("Raise error when version is gpdb but template does not exist", dict(scenario=8)) ] def setUp(self): @@ -40,6 +43,12 @@ class TestVersionedTemplateLoader(BaseTestGenerator): self.test_get_source_when_version_is_9_0_and_there_are_templates_for_9_1_and_9_2_returns_default_template() if self.scenario == 5: self.test_raise_not_found_exception_when_postgres_version_less_than_all_available_sql_templates() + if self.scenario == 6: + self.test_get_source_when_the_version_is_gpdb_5_0_returns_gpdb_5_0_template() + if self.scenario == 7: + self.test_get_source_when_the_version_is_gpdb_5_0_returns_default_template() + if self.scenario == 8: + self.test_raise_not_found_exception_when_the_version_is_gpdb_template_not_exist() def test_get_source_returns_a_template(self): expected_content = "Some SQL" \ @@ -86,6 +95,31 @@ class TestVersionedTemplateLoader(BaseTestGenerator): except TemplateNotFound: return + def test_get_source_when_the_version_is_gpdb_5_0_returns_gpdb_5_0_template(self): + expected_content = "Some default SQL for GPDB\n" + # For cross platform we join the SQL path (This solves the slashes issue) + sql_path = os.path.join("some_feature", "sql", "gpdb_5.0_plus", "some_action_with_gpdb_5_0.sql") + content, filename, up_to_dateness = self.loader.get_source(None, "some_feature/sql/#gpdb#80323#/some_action_with_gpdb_5_0.sql") + + self.assertEqual(expected_content, str(content).replace("\r", "")) + self.assertIn(sql_path, filename) + + def test_get_source_when_the_version_is_gpdb_5_0_returns_default_template(self): + expected_content = "Some default SQL" + # For cross platform we join the SQL path (This solves the slashes issue) + sql_path = os.path.join("some_feature", "sql", "default", "some_action_with_default.sql") + content, filename, up_to_dateness = self.loader.get_source(None, "some_feature/sql/#gpdb#80323#/some_action_with_default.sql") + + self.assertEqual(expected_content, str(content).replace("\r", "")) + self.assertIn(sql_path, filename) + + def test_raise_not_found_exception_when_the_version_is_gpdb_template_not_exist(self): + try: + self.loader.get_source(None, "some_feature/sql/#gpdb#50100#/some_action.sql") + self.fail("No exception raised") + except TemplateNotFound: + return + class FakeApp(Flask): def __init__(self): diff --git a/web/pgadmin/utils/versioned_template_loader.py b/web/pgadmin/utils/versioned_template_loader.py index d8cc1a11..1570353e 100644 --- a/web/pgadmin/utils/versioned_template_loader.py +++ b/web/pgadmin/utils/versioned_template_loader.py @@ -13,9 +13,9 @@ from jinja2 import TemplateNotFound class VersionedTemplateLoader(DispatchingJinjaLoader): def get_source(self, environment, template): - template_path_parts = template.split("#", 2) + template_path_parts = template.split("#", 3) - server_versions = ( + postgres_versions = ( {'name': "10_plus", 'number': 100000}, {'name': "9.6_plus", 'number': 90600}, {'name': "9.5_plus", 'number': 90500}, @@ -27,18 +27,29 @@ class VersionedTemplateLoader(DispatchingJinjaLoader): {'name': "default", 'number': 0} ) + gpdb_versions = ( + {'name': "gpdb_5.0_plus", 'number': 80323}, + {'name': "default", 'number': 0} + ) + + server_versions = postgres_versions if len(template_path_parts) == 1: return super(VersionedTemplateLoader, self).get_source(environment, template) + + if len(template_path_parts) == 4: + path_start, server_type, specified_version_number, file_name = template_path_parts + if server_type == 'gpdb': + server_versions = gpdb_versions else: - for server_version in server_versions: - path_start, specified_version_number, file_name = template_path_parts - - if server_version['number'] > int(specified_version_number): - continue - - template_path = path_start + '/' + server_version['name'] + '/' + file_name - try: - return super(VersionedTemplateLoader, self).get_source(environment, template_path) - except TemplateNotFound: - continue - raise TemplateNotFound(template) \ No newline at end of file + path_start, specified_version_number, file_name = template_path_parts + + for server_version in server_versions: + if server_version['number'] > int(specified_version_number): + continue + + template_path = path_start + '/' + server_version['name'] + '/' + file_name + try: + return super(VersionedTemplateLoader, self).get_source(environment, template_path) + except TemplateNotFound: + continue + raise TemplateNotFound(template)