public inbox for [email protected]  
help / color / mirror / Atom feed
From: Akshay Joshi <[email protected]>
To: Ashesh Vashi <[email protected]>
Cc: Harshal Dhumal <[email protected]>
Cc: pgadmin-hackers <[email protected]>
Cc: Dave Page <[email protected]>
Cc: Robert Eckhardt <[email protected]>
Cc: Shirley Wang <[email protected]>
Subject: Re: [pgadmin-hackers] Declarative partitioning in pgAdmin4
Date: Mon, 3 Jul 2017 15:14:35 +0530
Message-ID: <CANxoLDeZ6YO5_yXX9A12uafA9BS32nMKY-LwUSqxWKhSr21gig@mail.gmail.com> (raw)
In-Reply-To: <CAG7mmowUTNuwLexb+kFPPix0XHEaBAgMthtzN8H6OBAat0Zuyg@mail.gmail.com>
References: <CANxoLDcZND0pjXtrDKRip2xjddzjWiMgY2AMmrqqFE_Yu4+tHw@mail.gmail.com>
	<CA+OCxowUuaNRX9jHmEVFpqT7JCbjn6vaxw+JJ6yrvVp69FZscg@mail.gmail.com>
	<CAPG3WN5NY-Xsa_+6HUQ3NMU_n7jRgJ8L6rjHfyzSLSHS=zZC0Q@mail.gmail.com>
	<CA+OCxoy1v+mq2P4ZL2v7mmyHmjwQmL=v8RR8CSRra_SV96nJDQ@mail.gmail.com>
	<CANxoLDeBGRmq_kUUNNySXimzJO2Ebj0aQBdjNM+0JvP3_Yr9Dw@mail.gmail.com>
	<CAAtBm9Ve2FX4_jY9tv11UqK2BhNoLn118aeT4y=TieSAovL+AA@mail.gmail.com>
	<CA+OCxozkEdTmVUtJEBdHT97EbiUK_+cwW+rv21tuHyxSnN3HOg@mail.gmail.com>
	<CAAtBm9UHyp+bkxcyYL+1qb9knps_cdh6N0tvwMy5uY-eVjWcPg@mail.gmail.com>
	<CANxoLDdgp46uAZzda+cHBn16YibodXgtyH7O1hp39TKT=cv_ig@mail.gmail.com>
	<CA+OCxowpGBLT1q2DzL9VpRG5So8zYssP9SAdd=3Mc6dk8_-p7A@mail.gmail.com>
	<CANxoLDdP945GEfzeYaPjO41D4VoRN2kDMVhHZCOqCXWKegSEHw@mail.gmail.com>
	<CA+OCxowCzLAFybtfnsay9NB0BFORP5yXiitruxh9tvMoADNKRQ@mail.gmail.com>
	<CANxoLDcqudMZ5j-30EcFEL9KpQxyvrMWo0mVrWdg0p6_8e7peQ@mail.gmail.com>
	<CA+OCxow5pXNkDxrL1dbWbheJjpSseefSdvUs5tiwx7k5o3vB7Q@mail.gmail.com>
	<CANxoLDeNovspn8mm0XuYh+F2ShGotwRCAikU5JY9qF1GgFQ9rg@mail.gmail.com>
	<CA+OCxowtH1WJpXA1MKSLrzx_qbKAA36GTEk1t5=3VAS8fegBiA@mail.gmail.com>
	<CANxoLDeLHGvz0NxH_MM7dCe0muA8Sxe54V65b18iHTAESzt97g@mail.gmail.com>
	<CANxoLDeuXKCqrdNwiBut5m7FKQwzRjbPrqR6wHf8qKqgLDnwgQ@mail.gmail.com>
	<CAPG3WN4tiMGoFadBZ9KjB8NfNDVfvDnfUHhS=aya5A0o-jZ3Xw@mail.gmail.com>
	<CANxoLDfN_RvNc0AsVCtrDC-03L53crHzE8JZjmxna3f08KWVqw@mail.gmail.com>
	<CAPG3WN5QA88fNmY4jZZhBY+HUn2FAKecHuvyFjnq2x_vGu4_0w@mail.gmail.com>
	<CANxoLDfjy6sWQVHy5m5Rj1R5_=x_XwPzz6Mndj3xXfnEYpU_zg@mail.gmail.com>
	<CAPG3WN7haKwrQzrgVh7JSunGcP9_6wj=_q_C9J-yYgsZbhWmEw@mail.gmail.com>
	<CANxoLDeZ-izo=RSaHRnFNaAAQjxhd9-x6stx5FyLYU2ZA3A3vA@mail.gmail.com>
	<CAPG3WN6sKefWWYfg9A5=f-QOO9HAsg7krsuQ6FZwvojEuvSjCA@mail.gmail.com>
	<CAAtBm9Xw0qpvqRUb87AoSDdu56iaS8TaoVym3KkBJGjOgLU8cA@mail.gmail.com>
	<CANxoLDegWFzkbUi=8KSL-3cPb0masCjD1HwxaMDhV6fs2uOObw@mail.gmail.com>
	<CAAtBm9VpHahO2pbPM_ATowUU-YLT--RwWHmvW1Q+BtUGiCetyA@mail.gmail.com>
	<CANxoLDc53XkKDO=8FHG1i7KnvPCCiR2-1DjCTQoV9_K4Z11pRQ@mail.gmail.com>
	<CA+OCxoyEAPAra-nkS4qPVYEk3hHyVfRN-FQFPRfjSPrshwhsUg@mail.gmail.com>
	<CAPG3WN72DS8gQmrFR_nBObYaeMaxiqVuyjsVqHaZR1BT4LDqHg@mail.gmail.com>
	<CA+OCxozRODSQ9mdLnJWq4cbgHthQ9EqE7AE80kLbi6YPHBQMYg@mail.gmail.com>
	<CAAtBm9Ua5WMPnXRb87Dr3+FMeuaSWsHSgpYX8AB=TS+PF63pPw@mail.gmail.com>
	<CA+OCxozEKKgCNL9ng7KegYYeFdTU6hy+TdQFBp80W=Ew4XDesg@mail.gmail.com>
	<CAAtBm9V89ndB8ZqU0MPsAsUQ-RMEzbjaG2nFfMmFr1vtaY=v=g@mail.gmail.com>
	<CANxoLDeC9e+=ESBzoCSQeg4zgxwTz5zGG8HwYs9JNr90x4a-tA@mail.gmail.com>
	<CA+OCxoy3PV8iH8OrpH=yXWCR3GgHQ1v4tqiXpVMhD5Dg_fQhBQ@mail.gmail.com>
	<CAG7mmow7a1fhhL1WoWZFUDCe4mro+C_Gt=VCrA4db80e2xf1Aw@mail.gmail.com>
	<CA+OCxoxONjMu5BPgnFJsZApjPHC1owrNxkZOvUxLwp3nmN15=A@mail.gmail.com>
	<CANxoLDcP71Fy-wG4ahw_ru-tKd0bigg-c+vqKxSHjnPeHKH4YQ@mail.gmail.com>
	<CAPG3WN5vDsNnkQud-o08ebkUoXcKU1PPgEjNC-Xe7UrZgxGeQw@mail.gmail.com>
	<CANxoLDck4-6uT8QsZWwc+VtWBbuG2HgUPsgSh6WhvV=r5zJBeQ@mail.gmail.com>
	<CAPG3WN4imcBJ+OPpJtarhB_AqnDiHL-+upMSZaY=vafax+cc=Q@mail.gmail.com>
	<CAFiP3vzws9ZjotnQVM+VX72+h38SgfhSGiEANURLeJw5gAfKhA@mail.gmail.com>
	<CAG7mmozigGHVUK7Mi0CpLbnZRwJnghauMM_EyP4S06ka1FSnCw@mail.gmail.com>
	<CAG7mmowUTNuwLexb+kFPPix0XHEaBAgMthtzN8H6OBAat0Zuyg@mail.gmail.com>
List-Unsubscribe: <https://lists.postgresql.org/manage/>, <mailto:[email protected]>

Hi Ashesh

On Fri, Jun 30, 2017 at 12:46 PM, Ashesh Vashi <
[email protected]> wrote:

> On Thu, Jun 29, 2017 at 5:02 PM, Ashesh Vashi <
> [email protected]> wrote:
>
>> Hi Harshal,
>>
>> These are initial review comments.
>> 1.
>> Please share a separate patch for generic code changes from this patch
>> for the following files:
>> - web/pgadmin/tools/user_management/templates/user_management/
>> js/user_management.js
>> - web/pgadmin/static/js/backform.pgadmin.js
>> - web/pgadmin/static/js/backgrid.pgadmin.js
>>
>> This should be committed as separate functionality, and should not be
>> part of this commit.
>>
>
      Committed.

>
>> 2.
>> Please put a space after a colon (:) in javascript object definition.
>> i.e.
>> {cell: Backgrid.Extension.StringDepCell, cellHeaderClasses:
>> 'width_percent_30'}
>>
>> 3.
>> Conversion of ptid (partition table OID) to tid (table OID) for its
>> children must not be in 'web/pgadmin/browser/utils.py'  file.
>> Please create a inherited class of PGChildNodeView, and extend the
>> functionality in it, and use it as the base class for all children of table.
>>
>> I will keep you posted for further review comments.
>>
> 4.
> URL definition of the javascript for tables & partition tables utility
> must be exposed from the table/partition table module, and not from the
> database module.
> i.e.
> No changes should be done in the database module for this feature. Hence -
> I don't expect any change in the file:
> web/pgadmin/browser/server_groups/servers/databases/__init__.py
>

    Fixed.

   Apart from above this patch contains test cases as well.

>
> -- Thanks, Ashesh
>
>>
>>
>> --
>>
>> Thanks & Regards,
>>
>> Ashesh Vashi
>> EnterpriseDB INDIA: Enterprise PostgreSQL Company
>> <http://www.enterprisedb.com;
>>
>>
>> *http://www.linkedin.com/in/asheshvashi*
>> <http://www.linkedin.com/in/asheshvashi;
>>
>> On Fri, Jun 23, 2017 at 6:55 PM, Harshal Dhumal <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> Please find attached patch for partition support.
>>>
>>> This patch includes all the work done by Akashy and support for child
>>> nodes (constraints, rules, index, triggers and partition itself ) under
>>> partition node.
>>>
>>>
>>> Thanks,
>>>
>>> --
>>> *Harshal Dhumal*
>>> *Sr. Software Engineer*
>>>
>>> EnterpriseDB India: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>> On Tue, Jun 20, 2017 at 12:16 AM, Shirley Wang <[email protected]> wrote:
>>>
>>>>
>>>>
>>>> On Mon, Jun 19, 2017 at 1:59 AM Akshay Joshi <
>>>> [email protected]> wrote:
>>>>
>>>>> On Fri, Jun 16, 2017 at 11:16 PM, Shirley Wang <[email protected]>
>>>>> wrote:
>>>>>
>>>>>> Looks good. I noticed people clicking back and forth to the columns
>>>>>> tab to remember which columns they've created while filling out the
>>>>>> Expressions column. It might be better to have a list of the columns and
>>>>>> the datatype above the 'Partition Keys' subnode and have columns as a type
>>>>>> field rather than a drop down.
>>>>>>
>>>>>
>>>>>    I think we should not duplicate that data as we already have all
>>>>> the information on "Columns" tab and by providing drop down user can select
>>>>> columns from there only.
>>>>>
>>>>>>
>>>>>> Also, I think the fields someone sees after selecting the Key type
>>>>>> needs to depend on what they select. Seeing both Column and Expressions
>>>>>> type field might lead someone to think they need to fill out both fields.
>>>>>>
>>>>>
>>>>>    We can't, because user can select one column and provide an
>>>>> expression as partition key in this case we will have to show both the
>>>>> columns in subnode control. Anyways when user select columns I have
>>>>> disabled the expression cell and if user selects expression column cell is
>>>>> disabled.
>>>>>
>>>>
>>>> Ah I see what you mean. What I meant was that the column would change
>>>> depending on if someone selects Column or Expressions from the dropdown
>>>> [image: expression.png]
>>>> Can a user select more than one key type? The use case I can see where
>>>> hiding 'Columns' or 'Expressions' would fail is if someone can create an
>>>> expression key type and a column key type.
>>>>
>>>> Disabling a feature is one way to guide user behavior, but it doesn't
>>>> provide enough context for someone to understand why it's disabled. It's
>>>> better to only display what is absolutely necessary and hide fields that
>>>> are unrelated to the workflow.
>>>>
>>>> Typically, disabling a UI element is useful when that disabled UI
>>>> element also provides some context or value while disabled. In this case,
>>>> I'm not sure it is.
>>>>
>>>> If hiding options isn't possible, providing some text in the fields
>>>> (like N/A or --) would be helpful.
>>>>
>>>>
>>>>
>>>>>
>>>>>> [image: coluns_partitioning.png]
>>>>>> When is the 'In' column in the Partitions subnode enabled?
>>>>>>
>>>>>
>>>>>     In case of 'List' Partition.
>>>>>
>>>>
>>>> It would improve the experience if the 'In' column was removed when a
>>>> user selects 'Range' partitions then. And then if a user is creating a
>>>> 'List' partition, 'From/To' should be hidden. In this case, 'From/To' and
>>>> 'In' are dependent on that first drop down step, so seeing 'In' while on
>>>> 'Range partitions' (and 'From/To' on 'List partitions') is not providing
>>>> any value.
>>>>
>>>>
>>>>>
>>>>>> For the NoteControl on the bottom, what do 'Mode Control' or 'Attach
>>>>>> Mode' refer to? And how can I tell the difference between 'Create Mode' and
>>>>>> 'Edit Mode'?
>>>>>>
>>>>>
>>>>>    'Mode control' is a switch control in subnode control that should
>>>>> be "Mode switch control". 'Create Mode' is when user creates the new table
>>>>> by clicking create-> table and 'Edit Mode' is when user open the properties
>>>>> dialog for the existing table. In case of 'Edit Mode' there are two ways
>>>>> user can create/attach partitions. In Attach mode we will identify and list
>>>>> down the suitable tables to be attached.
>>>>>
>>>>
>>>> I see. Describing these various states is great in case a user needs
>>>> it. What are your thoughts on having it live in the documentation of
>>>> pgAdmin4 rather than in the dialog? This seems to be the established
>>>> pattern for all other explanations.
>>>>
>>>>>
>>>
>>
>


-- 
*Akshay Joshi*
*Principal Software Engineer *



*Phone: +91 20-3058-9517Mobile: +91 976-788-8246*


Attachments:

  [image/png] expression.png (69.8K, 3-expression.png)
  download | view image

  [image/png] coluns_partitioning.png (78.6K, 4-coluns_partitioning.png)
  download | view image

  [application/octet-stream] Partition_v5.patch (369.9K, 5-Partition_v5.patch)
  download | inline diff:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/__init__.py
index e40c787..4dc73f5 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/__init__.py
@@ -14,7 +14,8 @@ import re
 from functools import wraps
 
 import pgadmin.browser.server_groups.servers as servers
-from flask import render_template, current_app, request, jsonify
+from flask import render_template, make_response, current_app, request,\
+    jsonify
 from flask_babel import gettext as _
 from pgadmin.browser.collection import CollectionNodeModule
 from pgadmin.browser.server_groups.servers.databases.utils import \
@@ -86,6 +87,7 @@ class DatabaseModule(CollectionNodeModule):
         """
         return False
 
+
 blueprint = DatabaseModule(__name__)
 
 
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js
index 0e90997..ef496e7 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.js
@@ -145,6 +145,16 @@ define('pgadmin.node.schema', [
     group: gettext('Table'), mode: ['edit', 'create'],
     type: 'switch',
     disabled: function(m) {
+      // If table is partitioned table then disabled it.
+      if (m.top && m.top.get('is_partitioned')) {
+        // We also need to unset rest of all
+        setTimeout(function() {
+          m.set('autovacuum_custom', false);
+        }, 10);
+
+        return true;
+      }
+
       if(!m.top.inSchema.apply(this, [m])) {
         return false;
       }
@@ -459,6 +469,32 @@ define('pgadmin.node.schema', [
         return true;
       }
     });
+
+    pgBrowser.tableChildTreeNodeHierarchy = function(i) {
+      var idx = 0,
+          res = {},
+          t = pgBrowser.tree;
+
+      do {
+        d = t.itemData(i);
+        if (
+          d._type in pgBrowser.Nodes && pgBrowser.Nodes[d._type].hasId
+        ) {
+          if (d._type === 'partition' || d._type === 'table') {
+            if (!('table' in res)) {
+              res['table'] = _.extend({}, d, {'priority': idx});
+              idx -= 1;
+            }
+          } else {
+            res[d._type] = _.extend({}, d, {'priority': idx});
+            idx -= 1;
+          }
+        }
+        i = t.hasParent(i) ? t.parent(i) : null;
+      } while (i);
+
+      return res;
+    };
   }
 
   // Switch Cell with Deps (specifically for table children)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
index f6fa65e..bbbc8a9 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py
@@ -11,22 +11,16 @@
 
 import simplejson as json
 import re
-from functools import wraps
 
 import pgadmin.browser.server_groups.servers.databases as database
-from flask import render_template, request, jsonify
+from flask import render_template, request, jsonify, url_for
 from flask_babel import gettext
 from pgadmin.browser.server_groups.servers.databases.schemas.utils \
-    import SchemaChildModule, DataTypeReader, VacuumSettings, \
-    trigger_definition, parse_rule_definition
-from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
-    parse_priv_to_db
-from pgadmin.browser.utils import PGChildNodeView
+    import SchemaChildModule, DataTypeReader, VacuumSettings
+from pgadmin.browser.server_groups.servers.utils import parse_priv_to_db
 from pgadmin.utils.ajax import make_json_response, internal_server_error, \
     make_response as ajax_response, gone
-from pgadmin.utils.driver import get_driver
-
-from config import PG_DEFAULT_DRIVER
+from .utils import BaseTableView
 
 
 class TableModule(SchemaChildModule):
@@ -79,11 +73,22 @@ class TableModule(SchemaChildModule):
         """
         return database.DatabaseModule.NODE_TYPE
 
+    def get_own_javascripts(self):
+        scripts = SchemaChildModule.get_own_javascripts(self)
+
+        scripts.append({
+            'name': 'pgadmin.browser.table.partition.utils',
+            'path': url_for('browser.index') + 'table/static/js/partition.utils',
+            'when': 'database', 'is_template': False
+        })
+
+        return scripts
+
 
 blueprint = TableModule(__name__)
 
 
-class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
+class TableView(BaseTableView, DataTypeReader, VacuumSettings):
     """
     This class is responsible for generating routes for Table node
 
@@ -96,11 +101,6 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
       - This property defines (if javascript) exists for this node.
         Override this property for your own logic
 
-    * check_precondition()
-      - This function will behave as a decorator which will checks
-        database connection before running view, it will also attaches
-        manager,conn & template_path properties to self
-
     * list()
       - This function is used to list all the Table nodes within that
       collection.
@@ -149,10 +149,6 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
       - This function will generate dependent list to show it in dependent
         pane for the selected node.
 
-    * _formatter(data, tid)
-      - It will return formatted output of query result
-        as per client model format
-
     * get_types(self, gid, sid, did, scid)
       - This function will return list of types available for columns node
         via AJAX response
@@ -178,19 +174,6 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
     * get_toast_table_vacuum(gid, sid, did, scid=None, tid=None)
       - Fetch the default values for toast table auto-vacuum
 
-    * _columns_formatter(tid, data):
-      - It will return formatted output of query result
-        as per client model format for column node
-
-    * _index_constraints_formatter(self, did, tid, data):
-      - It will return formatted output of query result
-        as per client model format for index constraint node
-
-    * _cltype_formatter(type): (staticmethod)
-      - We need to remove [] from type and append it
-        after length/precision so we will send flag for
-        sql template
-
     * _parse_format_columns(self, data, mode=None):
        - This function will parse and return formatted list of columns
          added by user
@@ -252,71 +235,16 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         'get_access_methods': [{}, {'get': 'get_access_methods'}],
         'get_oper_class': [{}, {'get': 'get_oper_class'}],
         'get_operator': [{}, {'get': 'get_operator'}],
+        'get_attach_tables': [
+            {'get': 'get_attach_tables'},
+            {'get': 'get_attach_tables'}],
         'select_sql': [{'get': 'select_sql'}],
         'insert_sql': [{'get': 'insert_sql'}],
         'update_sql': [{'get': 'update_sql'}],
         'delete_sql': [{'get': 'delete_sql'}]
-
     })
 
-    def check_precondition(f):
-        """
-        This function will behave as a decorator which will checks
-        database connection before running view, it will also attaches
-        manager,conn & template_path properties to self
-        """
-
-        @wraps(f)
-        def wrap(*args, **kwargs):
-            # Here args[0] will hold self & kwargs will hold gid,sid,did
-            self = args[0]
-            driver = get_driver(PG_DEFAULT_DRIVER)
-            did = kwargs['did']
-            self.manager = driver.connection_manager(kwargs['sid'])
-            self.conn = self.manager.connection(did=kwargs['did'])
-            self.qtIdent = driver.qtIdent
-            self.qtTypeIdent = driver.qtTypeIdent
-            # We need datlastsysoid to check if current table is system table
-            self.datlastsysoid = self.manager.db_info[
-                did
-            ]['datlastsysoid'] if self.manager.db_info is not None and \
-                did in self.manager.db_info else 0
-
-            ver = self.manager.version
-            # Set the template path for the SQL scripts
-            self.template_path = 'table/sql/#{0}#'.format(ver)
-
-            # Template for Column ,check constraint and exclusion constraint node
-            self.column_template_path = 'column/sql/#{0}#'.format(ver)
-            self.check_constraint_template_path = 'check_constraint/sql/#{0}#'.format(ver)
-            self.exclusion_constraint_template_path = 'exclusion_constraint/sql/#{0}#'.format(ver)
-
-            # Template for PK & Unique constraint node
-            self.index_constraint_template_path = 'index_constraint/sql'
-
-            # Template for foreign key constraint node
-            self.foreign_key_template_path = 'foreign_key/sql/#{0}#'.format(ver)
-
-            # Template for index node
-            self.index_template_path = 'index/sql/#{0}#'.format(ver)
-
-            # Template for trigger node
-            self.trigger_template_path = 'trigger/sql/#{0}#'.format(ver)
-
-            # Template for rules node
-            self.rules_template_path = 'rules/sql'
-
-            # Supported ACL for table
-            self.acl = ['a', 'r', 'w', 'd', 'D', 'x', 't']
-
-            # Supported ACL for columns
-            self.column_acl = ['a', 'r', 'w', 'x']
-
-            return f(*args, **kwargs)
-
-        return wrap
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def list(self, gid, sid, did, scid):
         """
         This function is used to list all the table nodes within that collection.
@@ -330,7 +258,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         Returns:
             JSON of available table nodes
         """
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid,
                               datlastsysoid=self.datlastsysoid)
@@ -343,7 +271,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def node(self, gid, sid, did, scid, tid):
         """
         This function is used to list all the table nodes within that collection.
@@ -359,7 +287,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             JSON of available table nodes
         """
         res = []
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'nodes.sql']),
                               scid=scid, tid=tid)
         status, rset = self.conn.execute_2darray(SQL)
@@ -372,9 +300,10 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                 rset['rows'][0]['oid'],
                 scid,
                 rset['rows'][0]['name'],
-                icon="icon-table",
+                icon="icon-partition" if 'is_partitioned' in rset['rows'][0] and rset['rows'][0]['is_partitioned'] else "icon-table",
                 tigger_count=rset['rows'][0]['triggercount'],
-                has_enable_triggers=rset['rows'][0]['has_enable_triggers']
+                has_enable_triggers=rset['rows'][0]['has_enable_triggers'],
+                is_partitioned=rset['rows'][0]['is_partitioned'] if 'is_partitioned' in rset['rows'][0] else False
             )
 
         return make_json_response(
@@ -382,8 +311,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def nodes(self, gid, sid, did, scid):
         """
         This function is used to list all the table nodes within that collection.
@@ -398,7 +326,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             JSON of available table nodes
         """
         res = []
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'nodes.sql']),
                               scid=scid)
         status, rset = self.conn.execute_2darray(SQL)
@@ -411,9 +339,10 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                     row['oid'],
                     scid,
                     row['name'],
-                    icon="icon-table",
+                    icon="icon-partition" if 'is_partitioned' in row and row['is_partitioned'] else "icon-table",
                     tigger_count=row['triggercount'],
-                    has_enable_triggers=row['has_enable_triggers']
+                    has_enable_triggers=row['has_enable_triggers'],
+                    is_partitioned=row['is_partitioned'] if 'is_partitioned' in row else False
                 ))
 
         return make_json_response(
@@ -421,7 +350,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_all_tables(self, gid, sid, did, scid, tid=None):
         """
         Args:
@@ -435,7 +364,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             Returns the lits of tables required for constraints.
         """
         try:
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'get_tables_for_constraints.sql']),
                                   show_sysobj=self.blueprint.show_system_objects)
 
@@ -452,7 +381,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_table_vacuum(self, gid, sid, did, scid=None, tid=None):
         """
         Fetch the default values for table auto-vacuum
@@ -468,7 +397,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_toast_table_vacuum(self, gid, sid, did, scid=None, tid=None):
         """
         Fetch the default values for toast table auto-vacuum
@@ -484,7 +413,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_access_methods(self, gid, sid, did, scid, tid=None):
         """
         This function returns access methods.
@@ -518,7 +447,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_oper_class(self, gid, sid, did, scid, tid=None):
         """
 
@@ -555,7 +484,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_operator(self, gid, sid, did, scid, tid=None):
         """
 
@@ -593,506 +522,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    def _columns_formatter(self, tid, data):
-        """
-        Args:
-            tid: Table OID
-            data: dict of query result
-
-        Returns:
-            It will return formatted output of query result
-            as per client model format for column node
-        """
-        for column in data['columns']:
-
-            # We need to format variables according to client js collection
-            if 'attoptions' in column and column['attoptions'] is not None:
-                spcoptions = []
-                for spcoption in column['attoptions']:
-                    k, v = spcoption.split('=')
-                    spcoptions.append({'name': k, 'value': v})
-
-                column['attoptions'] = spcoptions
-
-            # Need to format security labels according to client js collection
-            if 'seclabels' in column and column['seclabels'] is not None:
-                seclabels = []
-                for seclbls in column['seclabels']:
-                    k, v = seclbls.split('=')
-                    seclabels.append({'provider': k, 'label': v})
-
-                column['seclabels'] = seclabels
-
-            if 'attnum' in column and column['attnum'] is not None and \
-                            column['attnum'] > 0:
-                # We need to parse & convert ACL coming from database to json format
-                SQL = render_template("/".join([self.column_template_path, 'acl.sql']),
-                                      tid=tid, clid=column['attnum'])
-                status, acl = self.conn.execute_dict(SQL)
-
-                if not status:
-                    return internal_server_error(errormsg=acl)
-
-                # We will set get privileges from acl sql so we don't need
-                # it from properties sql
-                column['attacl'] = []
-
-                for row in acl['rows']:
-                    priv = parse_priv_from_db(row)
-                    column.setdefault(row['deftype'], []).append(priv)
-
-                # we are receiving request when in edit mode
-                # we will send filtered types related to current type
-                present_type = column['cltype']
-
-                type_id = column['atttypid']
-
-                fulltype = self.get_full_type(
-                    column['typnspname'], column['typname'],
-                    column['isdup'], column['attndims'], column['atttypmod']
-                )
-
-                length = False
-                precision = False
-                if 'elemoid' in column:
-                    length, precision, typeval = self.get_length_precision(column['elemoid'])
-
-                # Set length and precision to None
-                column['attlen'] = None
-                column['attprecision'] = None
-
-                # If we have length & precision both
-                if length and precision:
-                    matchObj = re.search(r'(\d+),(\d+)', fulltype)
-                    if matchObj:
-                        column['attlen'] = matchObj.group(1)
-                        column['attprecision'] = matchObj.group(2)
-                elif length:
-                    # If we have length only
-                    matchObj = re.search(r'(\d+)', fulltype)
-                    if matchObj:
-                        column['attlen'] = matchObj.group(1)
-                        column['attprecision'] = None
-
-
-                SQL = render_template("/".join([self.column_template_path,
-                                                'is_referenced.sql']),
-                                      tid=tid, clid=column['attnum'])
-
-                status, is_reference = self.conn.execute_scalar(SQL)
-
-                edit_types_list = list()
-                # We will need present type in edit mode
-
-                if column['typnspname'] == "pg_catalog" or column['typnspname'] == "public":
-                    edit_types_list.append(present_type)
-                else:
-                    t = self.qtTypeIdent(self.conn, column['typnspname'], present_type)
-                    edit_types_list.append(t)
-                    column['cltype'] = t
-
-                if int(is_reference) == 0:
-                    SQL = render_template("/".join([self.column_template_path,
-                                                    'edit_mode_types.sql']),
-                                          type_id=type_id)
-                    status, rset = self.conn.execute_2darray(SQL)
-
-                    for row in rset['rows']:
-                        edit_types_list.append(row['typname'])
-                else:
-                    edit_types_list.append(present_type)
-
-                column['edit_types'] = edit_types_list
-                column['cltype'] = DataTypeReader.parse_type_name(column['cltype'])
-
-                if 'indkey' in column:
-                    # Current column
-                    attnum = str(column['attnum'])
-
-                    # Single/List of primary key column(s)
-                    indkey = str(column['indkey'])
-
-                    # We will check if column is in primary column(s)
-                    if attnum in indkey.split(" "):
-                        column['is_primary_key'] = True
-                    else:
-                        column['is_primary_key'] = False
-
-        return data
-
-    def _index_constraints_formatter(self, did, tid, data):
-        """
-        Args:
-            tid: Table OID
-            data: dict of query result
-
-        Returns:
-            It will return formatted output of query result
-            as per client model format for index constraint node
-        """
-
-        # We will fetch all the index constraints for the table
-        index_constraints = {
-            'p': 'primary_key', 'u': 'unique_constraint'
-        }
-
-        for ctype in index_constraints.keys():
-            data[index_constraints[ctype]] = []
-
-            sql = render_template("/".join([self.index_constraint_template_path,
-                                            'properties.sql']),
-                                  did=did, tid=tid,
-                                  constraint_type=ctype)
-            status, res = self.conn.execute_dict(sql)
-
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            for row in res['rows']:
-                result = row
-                sql = render_template(
-                    "/".join([self.index_constraint_template_path,
-                              'get_constraint_cols.sql']),
-                    cid=row['oid'],
-                    colcnt=row['indnatts'])
-                status, res = self.conn.execute_dict(sql)
-
-                if not status:
-                    return internal_server_error(errormsg=res)
-
-                columns = []
-                for r in res['rows']:
-                    columns.append({"column": r['column'].strip('"')})
-
-                result['columns'] = columns
-
-                # If not exists then create list and/or append into
-                # existing list [ Adding into main data dict]
-                data.setdefault(index_constraints[ctype], []).append(result)
-
-        return data
-
-    def _foreign_key_formatter(self, tid, data):
-        """
-        Args:
-            tid: Table OID
-            data: dict of query result
-
-        Returns:
-            It will return formatted output of query result
-            as per client model format for foreign key constraint node
-        """
-
-        # We will fetch all the index constraints for the table
-        sql = render_template("/".join([self.foreign_key_template_path,
-                                        'properties.sql']),
-                              tid=tid)
-
-        status, result = self.conn.execute_dict(sql)
-
-        if not status:
-            return internal_server_error(errormsg=result)
-
-        for fk in result['rows']:
-
-            sql = render_template("/".join([self.foreign_key_template_path,
-                                            'get_constraint_cols.sql']),
-                                  tid=tid,
-                                  keys=zip(fk['confkey'], fk['conkey']),
-                                  confrelid=fk['confrelid'])
-
-            status, res = self.conn.execute_dict(sql)
-
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            columns = []
-            cols = []
-            for row in res['rows']:
-                columns.append({"local_column": row['conattname'],
-                                "references": fk['confrelid'],
-                                "referenced": row['confattname']})
-                cols.append(row['conattname'])
-
-            fk['columns'] = columns
-
-            SQL = render_template("/".join([self.foreign_key_template_path,
-                                            'get_parent.sql']),
-                                  tid=fk['columns'][0]['references'])
-
-            status, rset = self.conn.execute_2darray(SQL)
-            if not status:
-                return internal_server_error(errormsg=rset)
-
-            fk['remote_schema'] = rset['rows'][0]['schema']
-            fk['remote_table'] = rset['rows'][0]['table']
-
-            coveringindex = self.search_coveringindex(tid, cols)
-
-            fk['coveringindex'] = coveringindex
-            if coveringindex:
-                fk['autoindex'] = True
-                fk['hasindex'] = True
-            else:
-                fk['autoindex'] = False
-                fk['hasindex'] = False
-            # If not exists then create list and/or append into
-            # existing list [ Adding into main data dict]
-            data.setdefault('foreign_key', []).append(fk)
-
-        return data
-
-    def _check_constraint_formatter(self, tid, data):
-        """
-        Args:
-            tid: Table OID
-            data: dict of query result
-
-        Returns:
-            It will return formatted output of query result
-            as per client model format for check constraint node
-        """
-
-        # We will fetch all the index constraints for the table
-        SQL = render_template("/".join([self.check_constraint_template_path,
-                                        'properties.sql']),
-                              tid=tid)
-
-        status, res = self.conn.execute_dict(SQL)
-
-        if not status:
-            return internal_server_error(errormsg=res)
-        # If not exists then create list and/or append into
-        # existing list [ Adding into main data dict]
-
-        data['check_constraint'] = res['rows']
-
-        return data
-
-    def _exclusion_constraint_formatter(self, did, tid, data):
-        """
-        Args:
-            tid: Table OID
-            data: dict of query result
-
-        Returns:
-            It will return formatted output of query result
-            as per client model format for exclusion constraint node
-        """
-
-        # We will fetch all the index constraints for the table
-        sql = render_template("/".join([self.exclusion_constraint_template_path,
-                                        'properties.sql']),
-                              did=did, tid=tid)
-
-        status, result = self.conn.execute_dict(sql)
-
-        if not status:
-            return internal_server_error(errormsg=result)
-
-        for ex in result['rows']:
-
-            sql = render_template("/".join([self.exclusion_constraint_template_path,
-                                            'get_constraint_cols.sql']),
-                                  cid=ex['oid'],
-                                  colcnt=ex['indnatts'])
-
-            status, res = self.conn.execute_dict(sql)
-
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            columns = []
-            for row in res['rows']:
-                if row['options'] & 1:
-                    order = False
-                    nulls_order = True if (row['options'] & 2) else False
-                else:
-                    order = True
-                    nulls_order = True if (row['options'] & 2) else False
-
-                columns.append({"column": row['coldef'].strip('"'),
-                                "oper_class": row['opcname'],
-                                "order": order,
-                                "nulls_order": nulls_order,
-                                "operator": row['oprname'],
-                                "col_type": row['datatype']
-                                })
-
-            ex['columns'] = columns
-            # If not exists then create list and/or append into
-            # existing list [ Adding into main data dict]
-            data.setdefault('exclude_constraint', []).append(ex)
-
-        return data
-
-    def search_coveringindex(self, tid, cols):
-        """
-
-        Args:
-          tid: Table id
-          cols: column list
-
-        Returns:
-
-        """
-
-        cols = set(cols)
-        SQL = render_template("/".join([self.foreign_key_template_path,
-                                        'get_constraints.sql']),
-                              tid=tid)
-        status, constraints = self.conn.execute_dict(SQL)
-
-        if not status:
-            raise Exception(constraints)
-
-        for costrnt in constraints['rows']:
-
-            sql = render_template(
-                "/".join([self.foreign_key_template_path, 'get_cols.sql']),
-                cid=costrnt['oid'],
-                colcnt=costrnt['indnatts'])
-            status, rest = self.conn.execute_dict(sql)
-
-            if not status:
-                return internal_server_error(errormsg=rest)
-
-            indexcols = set()
-            for r in rest['rows']:
-                indexcols.add(r['column'].strip('"'))
-
-            if len(cols - indexcols) == len(indexcols - cols) == 0:
-                return costrnt["idxname"]
-
-        return None
-
-    def _formatter(self, did, scid, tid, data):
-        """
-        Args:
-            data: dict of query result
-            scid: schema oid
-            tid: table oid
-
-        Returns:
-            It will return formatted output of query result
-            as per client model format
-        """
-        # Need to format security labels according to client js collection
-        if 'seclabels' in data and data['seclabels'] is not None:
-            seclabels = []
-            for seclbls in data['seclabels']:
-                k, v = seclbls.split('=')
-                seclabels.append({'provider': k, 'label': v})
-
-            data['seclabels'] = seclabels
-
-        # We need to parse & convert ACL coming from database to json format
-        SQL = render_template("/".join([self.template_path, 'acl.sql']),
-                              tid=tid, scid=scid)
-        status, acl = self.conn.execute_dict(SQL)
-        if not status:
-            return internal_server_error(errormsg=acl)
-
-        # We will set get privileges from acl sql so we don't need
-        # it from properties sql
-        for row in acl['rows']:
-            priv = parse_priv_from_db(row)
-            if row['deftype'] in data:
-                data[row['deftype']].append(priv)
-            else:
-                data[row['deftype']] = [priv]
-
-        # We will add Auto vacuum defaults with out result for grid
-        data['vacuum_table'] = self.parse_vacuum_data(self.conn, data, 'table')
-        data['vacuum_toast'] = self.parse_vacuum_data(self.conn, data, 'toast')
-
-        # Fetch columns for the table logic
-        #
-        # 1) Check if of_type and inherited tables are present?
-        # 2) If yes then Fetch all the columns for of_type and inherited tables
-        # 3) Add columns in columns collection
-        # 4) Find all the columns for tables and filter out columns which are
-        #   not inherited from any table & format them one by one
-
-        # Get of_type table columns and add it into columns dict
-        if data['typname']:
-            SQL = render_template("/".join([self.template_path,
-                                            'get_columns_for_table.sql']),
-                                  tname=data['typname'])
-
-            status, res = self.conn.execute_dict(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-            data['columns'] = res['rows']
-
-        # Get inherited table(s) columns and add it into columns dict
-        elif data['coll_inherits'] and len(data['coll_inherits']) > 0:
-            columns = []
-            # Return all tables which can be inherited & do not show
-            # system columns
-            SQL = render_template("/".join([self.template_path, 'get_inherits.sql']),
-                                  show_system_objects=False
-                                  )
-            status, rset = self.conn.execute_2darray(SQL)
-            if not status:
-                return internal_server_error(errormsg=rset)
-
-            for row in rset['rows']:
-                if row['inherits'] in data['coll_inherits']:
-                    # Fetch columns using inherited table OID
-                    SQL = render_template("/".join([self.template_path,
-                                                    'get_columns_for_table.sql']),
-                                          tid=row['oid'])
-                    status, res = self.conn.execute_dict(SQL)
-                    if not status:
-                        return internal_server_error(errormsg=res)
-                    columns.extend(res['rows'][:])
-            data['columns'] = columns
-
-        # We will fetch all the columns for the table using
-        # columns properties.sql, so we need to set template path
-        SQL = render_template("/".join([self.column_template_path,
-                                        'properties.sql']),
-                              tid=tid,
-                              show_sys_objects=False
-                              )
-
-        status, res = self.conn.execute_dict(SQL)
-        if not status:
-            return internal_server_error(errormsg=res)
-        all_columns = res['rows']
-
-        # Filter inherited columns from all columns
-        if 'columns' in data and len(data['columns']) > 0 \
-                and len(all_columns) > 0:
-            for row in data['columns']:
-                for i, col in enumerate(all_columns):
-                    # If both name are same then remove it
-                    # as it is inherited from other table
-                    if col['name'] == row['name']:
-                        # Remove same column from all_columns as
-                        # already have it columns collection
-                        del all_columns[i]
-
-            # If any column is added then update columns collection
-            if len(all_columns) > 0:
-                data['columns'] += all_columns
-        # If no inherited columns found then add all columns
-        elif len(all_columns) > 0:
-            data['columns'] = all_columns
-
-        if 'columns' in data and len(data['columns']) > 0:
-            data = self._columns_formatter(tid, data)
-
-        # Here we will add constraint in our output
-        data = self._index_constraints_formatter(did, tid, data)
-        data = self._foreign_key_formatter(tid, data)
-        data = self._check_constraint_formatter(tid, data)
-        data = self._exclusion_constraint_formatter(did, tid, data)
-
-        return data
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def properties(self, gid, sid, did, scid, tid):
         """
         This function will show the properties of the selected table node.
@@ -1109,7 +539,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             JSON of selected table node
         """
 
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid, tid=tid,
                               datlastsysoid=self.datlastsysoid)
@@ -1120,41 +550,19 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         if len(res['rows']) == 0:
                 return gone(gettext("The specified table could not be found."))
 
-        data = res['rows'][0]
-
-        data['vacuum_settings_str'] = ""
-
-        if data['table_vacuum_settings_str'] is not None:
-            data['vacuum_settings_str'] += data[
-                'table_vacuum_settings_str'].replace(',', '\n')
-
-        if data['toast_table_vacuum_settings_str'] is not None:
-            data['vacuum_settings_str'] += '\n' + '\n'.join(
-                ['toast_' + setting for setting in data[
-                    'toast_table_vacuum_settings_str'
-                ].split(',')]
-            )
-        data['vacuum_settings_str'] = data[
-            'vacuum_settings_str'
-        ].replace("=", " = ")
-
-        data = self._formatter(did, scid, tid, data)
-
-        return ajax_response(
-            response=data,
-            status=200
-        )
+        return super(TableView, self).properties(
+            gid, sid, did, scid, tid, res)
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def types(self, gid, sid, did, scid, tid=None, clid=None):
         """
         Returns:
             This function will return list of types available for column node
             for node-ajax-control
         """
-        condition = render_template("/".join([self.template_path,
-                                              'get_types_where_condition.sql']),
-                                    show_system_objects=self.blueprint.show_system_objects)
+        condition = render_template("/".join(
+            [self.table_template_path, 'get_types_where_condition.sql']),
+            show_system_objects=self.blueprint.show_system_objects)
 
         status, types = self.get_types(self.conn, condition, True)
 
@@ -1166,7 +574,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             status=200
         )
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_columns(self, gid, sid, did, scid, tid=None):
         """
         Returns the Table Columns.
@@ -1189,13 +597,14 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         data = request.args if request.args else None
         try:
             if data and 'tid' in data:
-                SQL = render_template("/".join([self.template_path,
+                SQL = render_template("/".join([self.table_template_path,
                                                 'get_columns_for_table.sql']),
                                       tid=data['tid'])
             elif data and 'tname' in data:
-                SQL = render_template("/".join([self.template_path,
-                                                'get_columns_for_table.sql']),
-                                      tname=data['tname'])
+                SQL = render_template("/".join(
+                    [self.table_template_path, 'get_columns_for_table.sql']),
+                    tname=data['tname']
+                )
 
             if SQL:
                 status, res = self.conn.execute_dict(SQL)
@@ -1211,7 +620,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_oftype(self, gid, sid, did, scid, tid=None):
         """
         Returns:
@@ -1220,10 +629,11 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         """
         res = [{'label': '', 'value': ''}]
         try:
-            SQL = render_template("/".join([self.template_path,
-                                            'get_oftype.sql']), scid=scid,
-                                  server_type=self.manager.server_type,
-                                  show_sys_objects=self.blueprint.show_system_objects)
+            SQL = render_template("/".join(
+                [self.table_template_path, 'get_oftype.sql']),
+                scid=scid,
+                server_type=self.manager.server_type,
+                show_sys_objects=self.blueprint.show_system_objects)
             status, rset = self.conn.execute_2darray(SQL)
             if not status:
                 return internal_server_error(errormsg=res)
@@ -1241,7 +651,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def get_inherits(self, gid, sid, did, scid, tid=None):
         """
         Returns:
@@ -1250,10 +660,11 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         """
         try:
             res = []
-            SQL = render_template("/".join([self.template_path, 'get_inherits.sql']),
-                                  show_system_objects=self.blueprint.show_system_objects,
-                                  tid=tid,
-                                  server_type=self.manager.server_type)
+            SQL = render_template("/".join(
+                [self.table_template_path, 'get_inherits.sql']),
+                show_system_objects=self.blueprint.show_system_objects,
+                tid=tid,
+                server_type=self.manager.server_type)
             status, rset = self.conn.execute_2darray(SQL)
             if not status:
                 return internal_server_error(errormsg=res)
@@ -1271,25 +682,29 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
-    def get_relations(self, gid, sid, did, scid, tid=None):
+    @BaseTableView.check_precondition
+    def get_attach_tables(self, gid, sid, did, scid, tid=None):
         """
         Returns:
-            This function will return list of tables available for like/relation
-            combobox while creating new table
+            This function will return list of tables available to be attached
+            to the partitioned table.
         """
-        res = [{'label': '', 'value': ''}]
         try:
-            SQL = render_template("/".join([self.template_path, 'get_relations.sql']),
-                                  show_sys_objects=self.blueprint.show_system_objects,
-                                  server_type=self.manager.server_type)
+            res = []
+            SQL = render_template("/".join(
+                [self.partition_template_path, 'get_attach_tables.sql']),
+                tid=tid
+            )
+
             status, rset = self.conn.execute_2darray(SQL)
             if not status:
                 return internal_server_error(errormsg=res)
+
             for row in rset['rows']:
                 res.append(
-                    {'label': row['like_relation'], 'value': row['like_relation']}
+                    {'label': row['table_name'], 'value': row['oid']}
                 )
+
             return make_json_response(
                 data=res,
                 status=200
@@ -1298,40 +713,33 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @staticmethod
-    def _cltype_formatter(data_type):
+    @BaseTableView.check_precondition
+    def get_relations(self, gid, sid, did, scid, tid=None):
         """
-
-        Args:
-            data_type: Type string
-
         Returns:
-            We need to remove [] from type and append it
-            after length/precision so we will send flag for
-            sql template
-        """
-        if '[]' in data_type:
-            return data_type[:-2], True
-        else:
-            return data_type, False
-
-    @staticmethod
-    def convert_length_precision_to_string(data):
+            This function will return list of tables available for like/relation
+            combobox while creating new table
         """
-        This function is used to convert length & precision to string
-        to handle case like when user gives 0 as length
-
-        Args:
-            data: Data from client
+        res = [{'label': '', 'value': ''}]
+        try:
+            SQL = render_template("/".join([
+                self.table_template_path, 'get_relations.sql']),
+                show_sys_objects=self.blueprint.show_system_objects,
+                server_type=self.manager.server_type)
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            for row in rset['rows']:
+                res.append(
+                    {'label': row['like_relation'], 'value': row['like_relation']}
+                )
+            return make_json_response(
+                data=res,
+                status=200
+            )
 
-        Returns:
-            Converted data
-        """
-        if 'attlen' in data and data['attlen'] is not None:
-            data['attlen'] = str(data['attlen'])
-        if 'attprecision' in data and data['attprecision'] is not None:
-            data['attprecision'] = str(data['attprecision'])
-        return data
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
 
     def _parse_format_columns(self, data, mode=None):
         """
@@ -1360,12 +768,12 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                             # check type for '[]' in it
                             c['cltype'], c['hasSqrBracket'] = self._cltype_formatter(c['cltype'])
 
-                        c = self.convert_length_precision_to_string(c)
+                        c = TableView.convert_length_precision_to_string(c)
 
                     data['columns'][action] = final_columns
         else:
-            # We need to exclude all the columns which are inherited from other tables
-            # 'CREATE' mode
+            # We need to exclude all the columns which are inherited from other
+            # tables 'CREATE' mode
             final_columns = []
 
             for c in columns:
@@ -1382,35 +790,13 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                     # check type for '[]' in it
                     c['cltype'], c['hasSqrBracket'] = self._cltype_formatter(c['cltype'])
 
-                c = self.convert_length_precision_to_string(c)
+                c = TableView.convert_length_precision_to_string(c)
 
             data['columns'] = final_columns
 
         return data
 
-    def check_and_convert_name_to_string(self, data):
-        """
-        This function will check and covert table to string incase
-        it is numeric
-
-        Args:
-            data: data dict
-
-        Returns:
-            Updated data dict
-        """
-        # For Python2, it can be int, long, float
-        if hasattr(str, 'decode'):
-            if isinstance(data['name'], (int, long, float)):
-                data['name'] = str(data['name'])
-        else:
-            # For Python3, it can be int, float
-            if isinstance(data['name'], (int, float)):
-                data['name'] = str(data['name'])
-        return data
-
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def create(self, gid, sid, did, scid):
         """
         This function will creates new the table object
@@ -1451,7 +837,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
         # Parse & format columns
         data = self._parse_format_columns(data)
-        data = self.check_and_convert_name_to_string(data)
+        data = TableView.check_and_convert_name_to_string(data)
 
         # 'coll_inherits' is Array but it comes as string from browser
         # We will convert it again to list
@@ -1474,9 +860,22 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                 c['remote_table'] = rset['rows'][0]['table']
 
         try:
-            SQL = render_template("/".join([self.template_path,
+            partitions_sql = ''
+            partitioned = False
+            if 'is_partitioned' in data and data['is_partitioned']:
+                data['relkind'] = 'p'
+                # create partition scheme
+                data['partition_scheme'] = self.get_partition_scheme(data)
+                partitions_sql = self.get_partitions_sql(data)
+                partitioned = True
+
+            SQL = render_template("/".join([self.table_template_path,
                                             'create.sql']),
                                   data=data, conn=self.conn)
+
+            # Append SQL for partitions
+            SQL += '\n' + partitions_sql
+
             status, res = self.conn.execute_scalar(SQL)
             if not status:
                 return internal_server_error(errormsg=res)
@@ -1490,7 +889,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                 data['name'] = data['name'][0:CONST_MAX_CHAR_COUNT]
 
             # Get updated schema oid
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                   'get_schema_oid.sql']), tname=data['name'])
 
             status, scid = self.conn.execute_scalar(SQL)
@@ -1498,7 +897,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                 return internal_server_error(errormsg=scid)
 
             # we need oid to to add object in tree at browser
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                   'get_oid.sql']), scid=scid, data=data)
             status, tid = self.conn.execute_scalar(SQL)
             if not status:
@@ -1509,13 +908,14 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                     tid,
                     scid,
                     data['name'],
-                    icon="icon-table"
+                    icon="icon-partition" if partitioned else "icon-table",
+                    is_partitioned=partitioned
                 )
             )
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def update(self, gid, sid, did, scid, tid):
         """
         This function will update an existing table object
@@ -1538,37 +938,23 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                 data[k] = v
 
         try:
-            SQL, name = self.get_sql(did, scid, tid, data)
-
-            SQL = SQL.strip('\n').strip(' ')
-            status, res = self.conn.execute_scalar(SQL)
+            SQL = render_template("/".join([self.table_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
             if not status:
                 return internal_server_error(errormsg=res)
 
-            SQL = render_template("/".join([self.template_path,
-                                  'get_schema_oid.sql']), tid=tid)
-            status, res = self.conn.execute_2darray(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
+            return super(TableView, self).update(
+                gid, sid, did, scid, tid, data, res)
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
 
-            # new schema id
-            scid = res['rows'][0]['scid']
-
-            return jsonify(
-                node=self.blueprint.generate_browser_node(
-                    tid,
-                    scid,
-                    name,
-                    icon="icon-%s" % self.node_type
-                )
-            )
-        except Exception as e:
-            return internal_server_error(errormsg=str(e))
-
-    @check_precondition
-    def delete(self, gid, sid, did, scid, tid):
-        """
-        This function will deletes the table object
+    @BaseTableView.check_precondition
+    def delete(self, gid, sid, did, scid, tid):
+        """
+        This function will deletes the table object
 
          Args:
            gid: Server Group ID
@@ -1585,7 +971,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             cascade = False
 
         try:
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'properties.sql']),
                                   did=did, scid=scid, tid=tid,
                                   datlastsysoid=self.datlastsysoid)
@@ -1606,7 +992,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
             data = res['rows'][0]
 
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'delete.sql']),
                                   data=data, cascade=cascade,
                                   conn=self.conn)
@@ -1626,7 +1012,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def truncate(self, gid, sid, did, scid, tid):
         """
         This function will truncate the table object
@@ -1638,43 +1024,22 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
            scid: Schema ID
            tid: Table ID
         """
-        # Below will decide if it's simple drop or drop with cascade call
-        data = request.form if request.form else json.loads(
-            request.data, encoding='utf-8'
-        )
-        # Convert str 'true' to boolean type
-        is_cascade = json.loads(data['cascade'])
 
         try:
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'properties.sql']),
                                   did=did, scid=scid, tid=tid,
                                   datlastsysoid=self.datlastsysoid)
             status, res = self.conn.execute_dict(SQL)
             if not status:
                 return internal_server_error(errormsg=res)
-            data = res['rows'][0]
 
-            SQL = render_template("/".join([self.template_path,
-                                            'truncate.sql']),
-                                  data=data, cascade=is_cascade)
-            status, res = self.conn.execute_scalar(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            return make_json_response(
-                success=1,
-                info=gettext("Table truncated"),
-                data={
-                    'id': tid,
-                    'scid': scid
-                }
-            )
+            return super(TableView, self).truncate(gid, sid, did, scid, tid, res)
 
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def enable_disable_triggers(self, gid, sid, did, scid, tid):
         """
         This function will enable/disable trigger(s) on the table object
@@ -1694,7 +1059,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         is_enable = json.loads(data['enable'])
 
         try:
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'properties.sql']),
                                   did=did, scid=scid, tid=tid,
                                   datlastsysoid=self.datlastsysoid)
@@ -1703,7 +1068,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                 return internal_server_error(errormsg=res)
             data = res['rows'][0]
 
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'enable_disable_trigger.sql']),
                                   data=data, is_enable_trigger=is_enable)
             status, res = self.conn.execute_scalar(SQL)
@@ -1723,7 +1088,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         except Exception as e:
             return internal_server_error(errormsg=str(e))
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def reset(self, gid, sid, did, scid, tid):
         """
         This function will reset statistics of table
@@ -1735,27 +1100,9 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
            scid: Schema ID
            tid: Table ID
         """
-        try:
-            SQL = render_template("/".join([self.template_path,
-                                            'reset_stats.sql']),
-                                  tid=tid)
-            status, res = self.conn.execute_scalar(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            return make_json_response(
-                success=1,
-                info=gettext("Table statistics have been reset"),
-                data={
-                    'id': tid,
-                    'scid': scid
-                }
-            )
-
-        except Exception as e:
-            return internal_server_error(errormsg=str(e))
+        return BaseTableView.reset_statistics(self, scid, tid)
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def msql(self, gid, sid, did, scid, tid=None):
         """
         This function will create modified sql for table object
@@ -1768,427 +1115,15 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
            tid: Table ID
         """
         data = dict()
+        res = None
         for k, v in request.args.items():
             try:
                 data[k] = json.loads(v, encoding='utf-8')
             except (ValueError, TypeError, KeyError):
                 data[k] = v
 
-        SQL, name = self.get_sql(did, scid, tid, data)
-        SQL = re.sub('\n{2,}', '\n\n', SQL)
-        SQL = SQL.strip('\n')
-        if SQL == '':
-            SQL = "--modified SQL"
-        return make_json_response(
-            data=SQL,
-            status=200
-        )
-
-    def get_index_constraint_sql(self, did, tid, data):
-        """
-         Args:
-           tid: Table ID
-           data: data dict coming from the client
-
-        Returns:
-        This function will generate modified sql for index constraints
-        (Primary Key & Unique)
-        """
-        sql = []
-        # We will fetch all the index constraints for the table
-        index_constraints = {
-            'p': 'primary_key', 'u': 'unique_constraint'
-        }
-
-        for ctype in index_constraints.keys():
-            # Check if constraint is in data
-            # If yes then we need to check for add/change/delete
-            if index_constraints[ctype] in data:
-                constraint = data[index_constraints[ctype]]
-                # If constraint(s) is/are deleted
-                if 'deleted' in constraint:
-                    for c in constraint['deleted']:
-                        c['schema'] = data['schema']
-                        c['table'] = data['name']
-
-                        # Sql for drop
-                        sql.append(
-                            render_template("/".join(
-                                [self.index_constraint_template_path,
-                                 'delete.sql']),
-                                data=c, conn=self.conn).strip('\n')
-                        )
-
-                if 'changed' in constraint:
-                    for c in constraint['changed']:
-                        c['schema'] = data['schema']
-                        c['table'] = data['name']
-
-                        properties_sql = render_template("/".join(
-                            [self.index_constraint_template_path, 'properties.sql']),
-                            did=did, tid=tid, cid=c['oid'], constraint_type=ctype)
-                        status, res = self.conn.execute_dict(properties_sql)
-                        if not status:
-                            return internal_server_error(errormsg=res)
-
-                        old_data = res['rows'][0]
-                        # Sql to update object
-                        sql.append(
-                            render_template("/".join([
-                                self.index_constraint_template_path,
-                                'update.sql']), data=c, o_data=old_data,
-                                conn=self.conn).strip('\n')
-                        )
-
-                if 'added' in constraint:
-                    for c in constraint['added']:
-                        c['schema'] = data['schema']
-                        c['table'] = data['name']
-
-                        # Sql to add object
-                        if self.validate_constrains(index_constraints[ctype], c):
-                            sql.append(
-                                render_template(
-                                    "/".join([self.index_constraint_template_path,
-                                              'create.sql']),
-                                    data=c, conn=self.conn,
-                                    constraint_name='PRIMARY KEY'
-                                    if ctype == 'p' else 'UNIQUE'
-                                ).strip('\n')
-                            )
-                        else:
-                            sql.append(
-                                gettext(
-                                    '-- definition incomplete for {0} constraint'.format(index_constraints[ctype])
-                                )
-                            )
-        if len(sql) > 0:
-            # Join all the sql(s) as single string
-            return '\n\n'.join(sql)
-        else:
-            return None
-
-    def get_foreign_key_sql(self, tid, data):
-        """
-         Args:
-           tid: Table ID
-           data: data dict coming from the client
-
-        Returns:
-        This function will generate modified sql for foreign key
-        """
-        sql = []
-        # Check if constraint is in data
-        # If yes then we need to check for add/change/delete
-        if 'foreign_key' in data:
-            constraint = data['foreign_key']
-            # If constraint(s) is/are deleted
-            if 'deleted' in constraint:
-                for c in constraint['deleted']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    # Sql for drop
-                    sql.append(
-                        render_template("/".join(
-                            [self.foreign_key_template_path,
-                             'delete.sql']),
-                            data=c, conn=self.conn).strip('\n')
-                    )
-
-            if 'changed' in constraint:
-                for c in constraint['changed']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    properties_sql = render_template("/".join(
-                        [self.foreign_key_template_path, 'properties.sql']),
-                        tid=tid, cid=c['oid'])
-                    status, res = self.conn.execute_dict(properties_sql)
-                    if not status:
-                        return internal_server_error(errormsg=res)
-
-                    old_data = res['rows'][0]
-                    # Sql to update object
-                    sql.append(
-                        render_template("/".join([
-                            self.foreign_key_template_path,
-                            'update.sql']), data=c, o_data=old_data,
-                            conn=self.conn).strip('\n')
-                    )
-
-                    if not self.validate_constrains('foreign_key', c):
-                        sql.append(
-                            gettext(
-                                '-- definition incomplete for foreign_key constraint'
-                            )
-                        )
-                        return '\n\n'.join(sql)
-
-                    if 'columns' in c:
-                        cols = []
-                        for col in c['columns']:
-                            cols.append(col['local_column'])
-
-                        coveringindex = self.search_coveringindex(tid, cols)
-
-                        if coveringindex is None and 'autoindex' in c and c['autoindex'] and \
-                                ('coveringindex' in c and
-                                         c['coveringindex'] != ''):
-                            sql.append(render_template(
-                                "/".join([self.foreign_key_template_path, 'create_index.sql']),
-                                data=c, conn=self.conn).strip('\n')
-                                       )
-
-            if 'added' in constraint:
-                for c in constraint['added']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    # Sql to add object
-                    # Columns
-
-                    if not self.validate_constrains('foreign_key', c):
-                        sql.append(
-                            gettext(
-                                '-- definition incomplete for foreign_key constraint'
-                            )
-                        )
-                        return '\n\n'.join(sql)
-
-                    SQL = render_template("/".join([self.foreign_key_template_path,
-                                                    'get_parent.sql']),
-                                          tid=c['columns'][0]['references'])
-                    status, rset = self.conn.execute_2darray(SQL)
-                    if not status:
-                        return internal_server_error(errormsg=rset)
-
-                    c['remote_schema'] = rset['rows'][0]['schema']
-                    c['remote_table'] = rset['rows'][0]['table']
-
-                    sql.append(
-                        render_template(
-                            "/".join([self.foreign_key_template_path,
-                                      'create.sql']),
-                            data=c, conn=self.conn
-                        ).strip('\n')
-                    )
-
-                    if c['autoindex']:
-                        sql.append(
-                            render_template(
-                                "/".join([self.foreign_key_template_path,
-                                          'create_index.sql']),
-                                data=c, conn=self.conn).strip('\n')
-                        )
-
-        if len(sql) > 0:
-            # Join all the sql(s) as single string
-            return '\n\n'.join(sql)
-        else:
-            return None
-
-    def get_check_constraint_sql(self, tid, data):
-        """
-         Args:
-           tid: Table ID
-           data: data dict coming from the client
-
-        Returns:
-          This function will generate modified sql for check constraint
-        """
-        sql = []
-        # Check if constraint is in data
-        # If yes then we need to check for add/change/delete
-        if 'check_constraint' in data:
-            constraint = data['check_constraint']
-            # If constraint(s) is/are deleted
-            if 'deleted' in constraint:
-                for c in constraint['deleted']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    # Sql for drop
-                    sql.append(
-                        render_template("/".join(
-                            [self.check_constraint_template_path,
-                             'delete.sql']),
-                            data=c, conn=self.conn).strip('\n')
-                    )
-
-            if 'changed' in constraint:
-                for c in constraint['changed']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    properties_sql = render_template("/".join(
-                        [self.check_constraint_template_path, 'properties.sql']),
-                        tid=tid, cid=c['oid'])
-                    status, res = self.conn.execute_dict(properties_sql)
-                    if not status:
-                        return internal_server_error(errormsg=res)
-
-                    old_data = res['rows'][0]
-                    # Sql to update object
-                    sql.append(
-                        render_template("/".join([
-                            self.check_constraint_template_path,
-                            'update.sql']), data=c, o_data=old_data,
-                            conn=self.conn).strip('\n')
-                    )
-
-            if 'added' in constraint:
-                for c in constraint['added']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    if not self.validate_constrains('check_constraint', c):
-                        sql.append(
-                            gettext(
-                                '-- definition incomplete for check_constraint'
-                            )
-                        )
-                        return '\n\n'.join(sql)
-
-                    sql.append(
-                        render_template(
-                            "/".join([self.check_constraint_template_path,
-                                      'create.sql']),
-                            data=c, conn=self.conn
-                        ).strip('\n')
-                    )
-
-        if len(sql) > 0:
-            # Join all the sql(s) as single string
-            return '\n\n'.join(sql)
-        else:
-            return None
-
-    def get_exclusion_constraint_sql(self, did, tid, data):
-        """
-         Args:
-           tid: Table ID
-           data: data dict coming from the client
-
-        Returns:
-          This function will generate modified sql for exclusion constraint
-        """
-        sql = []
-        # Check if constraint is in data
-        # If yes then we need to check for add/change/delete
-        if 'exclude_constraint' in data:
-            constraint = data['exclude_constraint']
-            # If constraint(s) is/are deleted
-            if 'deleted' in constraint:
-                for c in constraint['deleted']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    # Sql for drop
-                    sql.append(
-                        render_template("/".join(
-                            [self.exclusion_constraint_template_path,
-                             'delete.sql']),
-                            data=c, conn=self.conn).strip('\n')
-                    )
-
-            if 'changed' in constraint:
-                for c in constraint['changed']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    properties_sql = render_template("/".join(
-                        [self.exclusion_constraint_template_path, 'properties.sql']),
-                        did=did, tid=tid, cid=c['oid'])
-                    status, res = self.conn.execute_dict(properties_sql)
-                    if not status:
-                        return internal_server_error(errormsg=res)
-
-                    old_data = res['rows'][0]
-                    # Sql to update object
-                    sql.append(
-                        render_template("/".join([
-                            self.exclusion_constraint_template_path,
-                            'update.sql']), data=c, o_data=old_data,
-                            conn=self.conn).strip('\n')
-                    )
-
-            if 'added' in constraint:
-                for c in constraint['added']:
-                    c['schema'] = data['schema']
-                    c['table'] = data['name']
-
-                    if not self.validate_constrains('exclude_constraint', c):
-                        sql.append(
-                            gettext(
-                                '-- definition incomplete for exclusion_constraint'
-                            )
-                        )
-                        return '\n\n'.join(sql)
-
-                    sql.append(
-                        render_template(
-                            "/".join([self.exclusion_constraint_template_path,
-                                      'create.sql']),
-                            data=c, conn=self.conn
-                        ).strip('\n')
-                    )
-
-        if len(sql) > 0:
-            # Join all the sql(s) as single string
-            return u'\n\n'.join(sql)
-        else:
-            return None
-
-    def get_trigger_function_schema(self, data):
-        """
-        This function will return trigger function with schema name
-        """
-        # If language is 'edbspl' then trigger function should be
-        # 'Inline EDB-SPL' else we will find the trigger function
-        # with schema name.
-        if data['lanname'] == 'edbspl':
-            data['tfunction'] = 'Inline EDB-SPL'
-        else:
-            SQL = render_template(
-                "/".join(
-                    [self.trigger_template_path,'get_triggerfunctions.sql']
-                ),
-                tgfoid=data['tgfoid'],
-                show_system_objects=self.blueprint.show_system_objects
-            )
-
-            status, result = self.conn.execute_dict(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            # Update the trigger function which we have fetched with
-            # schema name
-            if 'rows' in result and len(result['rows']) > 0 and \
-                            'tfunctions' in result['rows'][0]:
-                data['tfunction'] = result['rows'][0]['tfunctions']
-        return data
-
-    def _format_args(self, args):
-        """
-        This function will format arguments.
-
-        Args:
-            args: Arguments
-
-        Returns:
-            Formated arguments for function
-        """
-        formatted_args = ["'{0}'".format(arg) for arg in args]
-        return ', '.join(formatted_args)
-
-    def get_sql(self, did, scid, tid, data):
-        """
-        This function will generate create/update sql from model data
-        coming from client
-        """
         if tid is not None:
-            SQL = render_template("/".join([self.template_path,
+            SQL = render_template("/".join([self.table_template_path,
                                             'properties.sql']),
                                   did=did, scid=scid, tid=tid,
                                   datlastsysoid=self.datlastsysoid)
@@ -2196,258 +1131,17 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             if not status:
                 return internal_server_error(errormsg=res)
 
-            old_data = res['rows'][0]
-            old_data = self._formatter(did, scid, tid, old_data)
-
-            # We will convert privileges coming from client required
-            if 'relacl' in data:
-                for mode in ['added', 'changed', 'deleted']:
-                    if mode in data['relacl']:
-                        data['relacl'][mode] = parse_priv_to_db(
-                            data['relacl'][mode], self.acl
-                        )
-
-            # If name is not present in request data
-            if 'name' not in data:
-                data['name'] = old_data['name']
-
-            data = self.check_and_convert_name_to_string(data)
-
-            # If name if not present
-            if 'schema' not in data:
-                data['schema'] = old_data['schema']
-
-            # Filter out new tables from list, we will send complete list
-            # and not newly added tables in the list from client
-            # so we will filter new tables here
-            if 'coll_inherits' in data:
-                p_len = len(old_data['coll_inherits'])
-                c_len = len(data['coll_inherits'])
-                # If table(s) added
-                if c_len > p_len:
-                    data['coll_inherits_added'] = list(
-                        set(data['coll_inherits']) - set(old_data['coll_inherits'])
-                    )
-                # If table(s)removed
-                elif c_len < p_len:
-                    data['coll_inherits_removed'] = list(
-                        set(old_data['coll_inherits']) - set(data['coll_inherits'])
-                    )
-                # Safe side verification,In case it happens..
-                # If user removes and adds same number of table
-                # eg removed one table and added one new table
-                elif c_len == p_len:
-                    data['coll_inherits_added'] = list(
-                        set(data['coll_inherits']) - set(old_data['coll_inherits'])
-                    )
-                    data['coll_inherits_removed'] = list(
-                        set(old_data['coll_inherits']) - set(data['coll_inherits'])
-                    )
-
-            SQL = render_template("/".join([self.template_path, 'update.sql']),
-                                  o_data=old_data, data=data, conn=self.conn)
-            # Removes training new lines
-            SQL = SQL.strip('\n') + '\n\n'
-
-            # Parse/Format columns & create sql
-            if 'columns' in data:
-                # Parse the data coming from client
-                data = self._parse_format_columns(data, mode='edit')
-
-                columns = data['columns']
-                column_sql = '\n'
-
-                # If column(s) is/are deleted
-                if 'deleted' in columns:
-                    for c in columns['deleted']:
-                        c['schema'] = data['schema']
-                        c['table'] = data['name']
-                        # Sql for drop column
-                        if 'inheritedfrom' not in c:
-                            column_sql += render_template("/".join(
-                                [self.column_template_path, 'delete.sql']),
-                                data=c, conn=self.conn).strip('\n') + '\n\n'
-
-                # If column(s) is/are changed
-                # Here we will be needing previous properties of column
-                # so that we can compare & update it
-                if 'changed' in columns:
-                    for c in columns['changed']:
-                        c['schema'] = data['schema']
-                        c['table'] = data['name']
-                        if 'attacl' in c:
-                            c['attacl'] = parse_priv_to_db(c['attacl'],
-                                                           self.column_acl)
-
-                        properties_sql = render_template("/".join([self.column_template_path,
-                                                                   'properties.sql']),
-                                                         tid=tid,
-                                                         clid=c['attnum'],
-                                                         show_sys_objects=self.blueprint.show_system_objects
-                                                         )
-
-                        status, res = self.conn.execute_dict(properties_sql)
-                        if not status:
-                            return internal_server_error(errormsg=res)
-                        old_data = res['rows'][0]
-
-                        old_data['cltype'], old_data['hasSqrBracket'] = self._cltype_formatter(old_data['cltype'])
-                        old_data = self.convert_length_precision_to_string(old_data)
-
-                        fulltype = self.get_full_type(
-                            old_data['typnspname'], old_data['typname'],
-                            old_data['isdup'], old_data['attndims'], old_data['atttypmod']
-                        )
-
-                        # If we have length & precision both
-                        matchObj = re.search(r'(\d+),(\d+)', fulltype)
-                        if matchObj:
-                            old_data['attlen'] = int(matchObj.group(1))
-                            old_data['attprecision'] = int(matchObj.group(2))
-                        else:
-                            # If we have length only
-                            matchObj = re.search(r'(\d+)', fulltype)
-                            if matchObj:
-                                old_data['attlen'] = int(matchObj.group(1))
-                                old_data['attprecision'] = None
-                            else:
-                                old_data['attlen'] = None
-                                old_data['attprecision'] = None
-
-                        old_data['cltype'] = DataTypeReader.parse_type_name(old_data['cltype'])
-
-                        # Sql for alter column
-                        if 'inheritedfrom' not in c:
-                            column_sql += render_template("/".join(
-                                [self.column_template_path, 'update.sql']),
-                                data=c, o_data=old_data, conn=self.conn).strip('\n') + '\n\n'
-
-                # If column(s) is/are added
-                if 'added' in columns:
-                    for c in columns['added']:
-                        c['schema'] = data['schema']
-                        c['table'] = data['name']
-                        # Sql for create column
-                        if 'attacl' in c:
-                            c['attacl'] = parse_priv_to_db(c['attacl'],
-                                                           self.column_acl)
-
-                        c = self.convert_length_precision_to_string(c)
-
-                        if 'inheritedfrom' not in c:
-                            column_sql += render_template("/".join(
-                                [self.column_template_path, 'create.sql']),
-                                data=c, conn=self.conn).strip('\n') + '\n\n'
-
-                # Combine all the SQL together
-                SQL += column_sql.strip('\n')
-
-            # Check if index constraints are added/changed/deleted
-            index_constraint_sql = self.get_index_constraint_sql(did, tid, data)
-            # If we have index constraint sql then ad it in main sql
-            if index_constraint_sql is not None:
-                SQL += '\n' + index_constraint_sql
-
-            # Check if foreign key(s) is/are added/changed/deleted
-            foreign_key_sql = self.get_foreign_key_sql(tid, data)
-            # If we have foreign key sql then ad it in main sql
-            if foreign_key_sql is not None:
-                SQL += '\n' + foreign_key_sql
-
-            # Check if check constraint(s) is/are added/changed/deleted
-            check_constraint_sql = self.get_check_constraint_sql(tid, data)
-            # If we have check constraint sql then ad it in main sql
-            if check_constraint_sql is not None:
-                SQL += '\n' + check_constraint_sql
-
-            # Check if exclusion constraint(s) is/are added/changed/deleted
-            exclusion_constraint_sql = self.get_exclusion_constraint_sql(did, tid, data)
-            # If we have check constraint sql then ad it in main sql
-            if exclusion_constraint_sql is not None:
-                SQL += '\n' + exclusion_constraint_sql
-
-        else:
-            required_args = [
-                'name'
-            ]
-
-            for arg in required_args:
-                if arg not in data:
-                    return gettext('-- definition incomplete')
-
-            # validate constraint data.
-            for key in ['primary_key', 'unique_constraint',
-                        'foreign_key', 'check_constraint',
-                        'exclude_constraint']:
-                if key in data and len(data[key]) > 0:
-                    for constraint in data[key]:
-                        if not self.validate_constrains(key, constraint):
-                            return gettext('-- definition incomplete for {0}'.format(key))
-
-            # We will convert privileges coming from client required
-            # in server side format
-            if 'relacl' in data:
-                data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
-
-            # Parse & format columns
-            data = self._parse_format_columns(data)
-            data = self.check_and_convert_name_to_string(data)
-
-            if 'foreign_key' in data:
-                for c in data['foreign_key']:
-                    SQL = render_template("/".join([self.foreign_key_template_path,
-                                                    'get_parent.sql']),
-                                          tid=c['columns'][0]['references'])
-                    status, rset = self.conn.execute_2darray(SQL)
-                    if not status:
-                        return internal_server_error(errormsg=rset)
-
-                    c['remote_schema'] = rset['rows'][0]['schema']
-                    c['remote_table'] = rset['rows'][0]['table']
-
-            # If the request for new object which do not have did
-            SQL = render_template("/".join([self.template_path, 'create.sql']),
-                                  data=data, conn=self.conn)
+        SQL, name = self.get_sql(did, scid, tid, data, res)
         SQL = re.sub('\n{2,}', '\n\n', SQL)
         SQL = SQL.strip('\n')
+        if SQL == '':
+            SQL = "--modified SQL"
+        return make_json_response(
+            data=SQL,
+            status=200
+        )
 
-        return SQL, data['name'] if 'name' in data else old_data['name']
-
-    @staticmethod
-    def validate_constrains(key, data):
-
-        if key == 'primary_key' or key == 'unique_constraint':
-            if 'columns' in data and len(data['columns']) > 0:
-                return True
-            else:
-                return False
-        elif key == 'foreign_key':
-            if 'oid' not in data:
-                for arg in ['columns']:
-                    if arg not in data:
-                        return False
-                    elif isinstance(data[arg], list) and len(data[arg]) < 1:
-                        return False
-
-                if 'autoindex' in data and data['autoindex'] and \
-                        ('coveringindex' not in data or
-                                                  data['coveringindex'] == ''):
-                    return False
-
-            return True
-
-        elif key == 'check_constraint':
-            for arg in ['consrc']:
-                if arg not in data or data[arg] == '':
-                    return False
-            return True
-
-        elif key == 'exclude_constraint':
-            pass
-
-        return True
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def dependents(self, gid, sid, did, scid, tid):
         """
         This function get the dependents and return ajax response
@@ -2460,43 +1154,9 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             scid: Schema ID
             tid: Table ID
         """
-        # Specific condition for column which we need to append
-        where = "WHERE dep.refobjid={0}::OID".format(tid)
-
-        dependents_result = self.get_dependents(
-            self.conn, tid
-        )
-
-        # Specific sql to run againt column to fetch dependents
-        SQL = render_template("/".join([self.template_path,
-                                        'depend.sql']), where=where)
+        return BaseTableView.get_table_dependents(self, tid)
 
-        status, res = self.conn.execute_dict(SQL)
-        if not status:
-            return internal_server_error(errormsg=res)
-
-        for row in res['rows']:
-            ref_name = row['refname']
-            if ref_name is None:
-                continue
-
-            dep_type = ''
-            dep_str = row['deptype']
-            if dep_str == 'a':
-                dep_type = 'auto'
-            elif dep_str == 'n':
-                dep_type = 'normal'
-            elif dep_str == 'i':
-                dep_type = 'internal'
-
-            dependents_result.append({'type': 'sequence', 'name': ref_name, 'field': dep_type})
-
-        return ajax_response(
-            response=dependents_result,
-            status=200
-        )
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def dependencies(self, gid, sid, did, scid, tid):
         """
         This function get the dependencies and return ajax response
@@ -2508,18 +1168,10 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
             did: Database ID
             scid: Schema ID
             tid: Table ID
-
         """
-        dependencies_result = self.get_dependencies(
-            self.conn, tid
-        )
+        return BaseTableView.get_table_dependencies(self, tid)
 
-        return ajax_response(
-            response=dependencies_result,
-            status=200
-        )
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def sql(self, gid, sid, did, scid, tid):
         """
         This function will creates reverse engineered sql for
@@ -2534,12 +1186,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         """
         main_sql = []
 
-        """
-        #####################################
-        # 1) Reverse engineered sql for TABLE
-        #####################################
-        """
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid, tid=tid,
                               datlastsysoid=self.datlastsysoid)
@@ -2552,250 +1199,10 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
         data = res['rows'][0]
 
-        # Table & Schema declaration so that we can use them in child nodes
-        schema = data['schema']
-        table = data['name']
-
-        data = self._formatter(did, scid, tid, data)
-
-        # Now we have all lis of columns which we need
-        # to include in our create definition, Let's format them
-        if 'columns' in data:
-            for c in data['columns']:
-                if 'attacl' in c:
-                    c['attacl'] = parse_priv_to_db(c['attacl'], self.column_acl)
-
-                # check type for '[]' in it
-                if 'cltype' in c:
-                    c['cltype'], c['hasSqrBracket'] = self._cltype_formatter(c['cltype'])
-
-        sql_header = u"-- Table: {0}\n\n-- ".format(self.qtIdent(self.conn,
-                                                                data['schema'],
-                                                                data['name']))
-
-        sql_header += render_template("/".join([self.template_path,
-                                                'delete.sql']),
-                                      data=data, conn=self.conn)
-
-        sql_header = sql_header.strip('\n')
-        sql_header += '\n'
-
-        # Add into main sql
-        main_sql.append(sql_header)
-
-        # Parse privilege data
-        if 'relacl' in data:
-            data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
-
-        # If the request for new object which do not have did
-        table_sql = render_template("/".join([self.template_path,
-                                              'create.sql']),
-                                    data=data, conn=self.conn, is_sql=True)
-
-        # Add into main sql
-        table_sql = re.sub('\n{2,}', '\n\n', table_sql)
-        main_sql.append(table_sql.strip('\n'))
-
-        """
-        ######################################
-        # 2) Reverse engineered sql for INDEX
-        ######################################
-        """
-
-        SQL = render_template("/".join([self.index_template_path,
-                                        'nodes.sql']), tid=tid)
-        status, rset = self.conn.execute_2darray(SQL)
-        if not status:
-            return internal_server_error(errormsg=rset)
-
-        for row in rset['rows']:
-
-            SQL = render_template("/".join([self.index_template_path,
-                                            'properties.sql']),
-                                  did=did, tid=tid, idx=row['oid'],
-                                  datlastsysoid=self.datlastsysoid)
-
-            status, res = self.conn.execute_dict(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            data = dict(res['rows'][0])
-            # Adding parent into data dict, will be using it while creating sql
-            data['schema'] = schema
-            data['table'] = table
-            # We also need to fecth columns of index
-            SQL = render_template("/".join([self.index_template_path,
-                                            'column_details.sql']),
-                                  idx=row['oid'])
-            status, rset = self.conn.execute_2darray(SQL)
-            if not status:
-                return internal_server_error(errormsg=rset)
-
-            # 'attdef' comes with quotes from query so we need to strip them
-            # 'options' we need true/false to render switch ASC(false)/DESC(true)
-            columns = []
-            cols = []
-            for col_row in rset['rows']:
-                # We need all data as collection for ColumnsModel
-                cols_data = {
-                    'colname': col_row['attdef'].strip('"'),
-                    'collspcname': col_row['collnspname'],
-                    'op_class': col_row['opcname'],
-                }
-                if col_row['options'][0] == 'DESC':
-                    cols_data['sort_order'] = True
-                columns.append(cols_data)
-
-                # We need same data as string to display in properties window
-                # If multiple column then separate it by colon
-                cols_str = col_row['attdef']
-                if col_row['collnspname']:
-                    cols_str += ' COLLATE ' + col_row['collnspname']
-                if col_row['opcname']:
-                    cols_str += ' ' + col_row['opcname']
-                if col_row['options'][0] == 'DESC':
-                    cols_str += ' DESC'
-                cols.append(cols_str)
-
-            # Push as collection
-            data['columns'] = columns
-            # Push as string
-            data['cols'] = ', '.join(cols)
-
-            sql_header = u"\n-- Index: {0}\n\n-- ".format(data['name'])
-
-            sql_header += render_template("/".join([self.index_template_path,
-                                                    'delete.sql']),
-                                          data=data, conn=self.conn)
-
-            index_sql = render_template("/".join([self.index_template_path,
-                                                  'create.sql']),
-                                        data=data, conn=self.conn)
-            index_sql += "\n"
-            index_sql += render_template("/".join([self.index_template_path,
-                                                   'alter.sql']),
-                                         data=data, conn=self.conn)
-
-            # Add into main sql
-            index_sql = re.sub('\n{2,}', '\n\n', index_sql)
-            main_sql.append(sql_header + '\n\n' + index_sql.strip('\n'))
-
-        """
-        ########################################
-        # 3) Reverse engineered sql for TRIGGERS
-        ########################################
-        """
-        SQL = render_template("/".join([self.trigger_template_path,
-                                        'nodes.sql']), tid=tid)
-        status, rset = self.conn.execute_2darray(SQL)
-        if not status:
-            return internal_server_error(errormsg=rset)
-
-        for row in rset['rows']:
-            trigger_sql = ''
-
-            SQL = render_template("/".join([self.trigger_template_path,
-                                            'properties.sql']),
-                                  tid=tid, trid=row['oid'],
-                                  datlastsysoid=self.datlastsysoid)
-
-            status, res = self.conn.execute_dict(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            data = dict(res['rows'][0])
-            # Adding parent into data dict, will be using it while creating sql
-            data['schema'] = schema
-            data['table'] = table
-
-            data = self.get_trigger_function_schema(data)
-
-            if len(data['custom_tgargs']) > 1:
-                # We know that trigger has more than 1 argument, let's join them
-                data['tgargs'] = self._format_args(data['custom_tgargs'])
-
-            if len(data['tgattr']) > 1:
-                columns = ', '.join(data['tgattr'].split(' '))
-
-                SQL = render_template("/".join([self.trigger_template_path,
-                                                'get_columns.sql']),
-                                      tid=tid, clist=columns)
-
-                status, rset = self.conn.execute_2darray(SQL)
-                if not status:
-                    return internal_server_error(errormsg=rset)
-                # 'tgattr' contains list of columns from table used in trigger
-                columns = []
-
-                for col_row in rset['rows']:
-                    columns.append({'column': col_row['name']})
-
-                data['columns'] = columns
-
-            data = trigger_definition(data)
-
-            sql_header = u"\n-- Trigger: {0}\n\n-- ".format(data['name'])
-
-            sql_header += render_template("/".join([self.trigger_template_path,
-                                                    'delete.sql']),
-                                          data=data, conn=self.conn)
-
-            # If the request for new object which do not have did
-            trigger_sql = render_template("/".join([self.trigger_template_path,
-                                                    'create.sql']),
-                                          data=data, conn=self.conn)
-
-            trigger_sql = sql_header + '\n\n' + trigger_sql.strip('\n')
-
-            # If trigger is disabled then add sql code for the same
-            if not data['is_enable_trigger']:
-                trigger_sql += '\n\n'
-                trigger_sql += render_template("/".join([
-                    self.trigger_template_path,
-                    'enable_disable_trigger.sql']),
-                    data=data, conn=self.conn)
-
-            # Add into main sql
-            trigger_sql = re.sub('\n{2,}', '\n\n', trigger_sql)
-            main_sql.append(trigger_sql)
-
-        """
-        #####################################
-        # 4) Reverse engineered sql for RULES
-        #####################################
-        """
-
-        SQL = render_template("/".join(
-            [self.rules_template_path, 'properties.sql']), tid=tid)
-
-        status, rset = self.conn.execute_2darray(SQL)
-        if not status:
-            return internal_server_error(errormsg=rset)
-
-        for row in rset['rows']:
-            rules_sql = '\n'
-            SQL = render_template("/".join(
-                [self.rules_template_path, 'properties.sql']
-            ), rid=row['oid'], datlastsysoid=self.datlastsysoid)
-
-            status, res = self.conn.execute_dict(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
-
-            res_data = parse_rule_definition(res)
-            rules_sql += render_template("/".join(
-                [self.rules_template_path, 'create.sql']),
-                data=res_data, display_comments=True)
-
-            # Add into main sql
-            rules_sql = re.sub('\n{2,}', '\n\n', rules_sql)
-            main_sql.append(rules_sql)
+        return BaseTableView.get_reverse_engineered_sql(
+            self, did, scid, tid, main_sql, data)
 
-        sql = '\n'.join(main_sql)
-
-        return ajax_response(response=sql.strip('\n'))
-
-    @check_precondition
+    @BaseTableView.check_precondition
     def select_sql(self, gid, sid, did, scid, tid):
         """
         SELECT script sql for the object
@@ -2810,7 +1217,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         Returns:
             SELECT Script sql for the object
         """
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid, tid=tid,
                               datlastsysoid=self.datlastsysoid)
@@ -2839,7 +1246,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         )
         return ajax_response(response=sql)
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def insert_sql(self, gid, sid, did, scid, tid):
         """
         INSERT script sql for the object
@@ -2854,7 +1261,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         Returns:
             INSERT Script sql for the object
         """
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid, tid=tid,
                               datlastsysoid=self.datlastsysoid)
@@ -2886,7 +1293,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
         return ajax_response(response=sql)
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def update_sql(self, gid, sid, did, scid, tid):
         """
         UPDATE script sql for the object
@@ -2901,7 +1308,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         Returns:
             UPDATE Script sql for the object
         """
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid, tid=tid,
                               datlastsysoid=self.datlastsysoid)
@@ -2935,7 +1342,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
         return ajax_response(response=sql)
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def delete_sql(self, gid, sid, did, scid, tid):
         """
         DELETE script sql for the object
@@ -2950,7 +1357,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         Returns:
             DELETE Script sql for the object
         """
-        SQL = render_template("/".join([self.template_path,
+        SQL = render_template("/".join([self.table_template_path,
                                         'properties.sql']),
                               did=did, scid=scid, tid=tid,
                               datlastsysoid=self.datlastsysoid)
@@ -2966,7 +1373,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
         return ajax_response(response=sql)
 
-    @check_precondition
+    @BaseTableView.check_precondition
     def statistics(self, gid, sid, did, scid, tid=None):
         """
         Statistics
@@ -2982,63 +1389,6 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         otherwise it will return statistics for all the tables in that
         schema.
         """
-
-        # Fetch schema name
-        status, schema_name = self.conn.execute_scalar(
-            render_template(
-                "/".join([self.template_path, 'get_schema.sql']),
-                conn=self.conn, scid=scid
-            )
-        )
-        if not status:
-            return internal_server_error(errormsg=schema_name)
-
-        if tid is None:
-            status, res = self.conn.execute_dict(
-                render_template(
-                    "/".join([self.template_path, 'coll_table_stats.sql']),
-                    conn=self.conn, schema_name=schema_name
-                )
-            )
-        else:
-            # For Individual table stats
-
-            # Check if pgstattuple extension is already created?
-            # if created then only add extended stats
-            status, is_pgstattuple = self.conn.execute_scalar("""
-            SELECT (count(extname) > 0) AS is_pgstattuple
-            FROM pg_extension
-            WHERE extname='pgstattuple'
-            """)
-            if not status:
-                return internal_server_error(errormsg=is_pgstattuple)
-
-            # Fetch Table name
-            status, table_name = self.conn.execute_scalar(
-                render_template(
-                    "/".join([self.template_path, 'get_table.sql']),
-                    conn=self.conn, scid=scid, tid=tid
-                )
-            )
-            if not status:
-                return internal_server_error(errormsg=table_name)
-
-            status, res = self.conn.execute_dict(
-                render_template(
-                    "/".join([self.template_path, 'stats.sql']),
-                    conn=self.conn, schema_name=schema_name,
-                    table_name=table_name,
-                    is_pgstattuple=is_pgstattuple, tid=tid
-                )
-            )
-
-        if not status:
-            return internal_server_error(errormsg=res)
-
-        return make_json_response(
-            data=res,
-            status=200
-        )
-
+        return BaseTableView.get_table_statistics(self, scid, tid)
 
 TableView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
index 179b961..70ffbd2 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/templates/column/js/column.js
@@ -86,6 +86,7 @@ define('pgadmin.node.column', [
 
   if (!pgBrowser.Nodes['column']) {
     pgBrowser.Nodes['column'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       parent_type: ['table', 'view', 'mview'],
       collection_type: ['coll-table', 'coll-view', 'coll-mview'],
       type: 'column',
@@ -228,6 +229,17 @@ define('pgadmin.node.column', [
               return false;
             }
 
+            // If table is partitioned table then disable
+            if (m.top && !_.isUndefined(m.top.get('is_partitioned')) &&
+              m.top.get('is_partitioned'))
+            {
+              setTimeout(function () {
+                m.set('is_primary_key', false);
+              }, 10);
+
+              return false;
+            }
+
             if(!m.inSchemaWithColumnCheck.apply(this, [m]) &&
               !_.isUndefined(name) && !_.isNull(name) && name !== '') {
               return true;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/tests/test_column_get.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/tests/test_column_get.py
index 713d999..4adfbef 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/tests/test_column_get.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/tests/test_column_get.py
@@ -24,7 +24,7 @@ from . import utils as columns_utils
 class ColumnGetTestCase(BaseTestGenerator):
     """This class will get column under table node."""
     scenarios = [
-        ('Fetch table Node URL', dict(url='/browser/column/obj/'))
+        ('Fetch columns under table node', dict(url='/browser/column/obj/'))
     ]
 
     def setUp(self):
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js
index b12d9d3..85f62f7 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/templates/check_constraint/js/check_constraint.js
@@ -10,6 +10,7 @@ define('pgadmin.node.check_constraints', [
   // Check Constraint Node
   if (!pgBrowser.Nodes['check_constraints']) {
     pgAdmin.Browser.Nodes['check_constraints'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       type: 'check_constraints',
       label: gettext('Check'),
       collection_type: 'coll-constraints',
@@ -18,7 +19,7 @@ define('pgadmin.node.check_constraints', [
       dialogHelp: url_for('help.static', {'filename': 'check_dialog.html'}),
       hasSQL: true,
       hasDepends: true,
-      parent_type: ['table'],
+      parent_type: ['table','partition'],
       Init: function() {
         // Avoid mulitple registration of menus
         if (this.initialized)
@@ -137,6 +138,18 @@ define('pgadmin.node.check_constraints', [
           'switch', cell: 'boolean', group: gettext('Definition'), mode:
           ['properties', 'create', 'edit'], min_version: 90200,
           disabled: function(m) {
+            // Disabled if table is a partitioned table.
+            if ((_.has(m , 'top') && !_.isUndefined(m.top) && m.top.get('is_partitioned')) ||
+                (_.has(m, 'node_info') && _.has(m.node_info, 'table') &&
+                _.has(m.node_info.table, 'is_partitioned') && m.node_info.table.is_partitioned)
+            ){
+              setTimeout(function(){
+                  m.set('connoinherit', false);
+              },10);
+
+              return true;
+            }
+
             return ((_.has(m, 'handler') &&
               !_.isUndefined(m.handler) &&
               !_.isUndefined(m.get('oid'))) || (_.isFunction(m.isNew) && !m.isNew()));
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js
index 814edce..605495d 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/templates/exclusion_constraint/js/exclusion_constraint.js
@@ -602,6 +602,7 @@ define('pgadmin.node.exclusion_constraint', [
   // Extend the browser's node class for exclusion constraint node
   if (!pgBrowser.Nodes['exclusion_constraint']) {
     pgAdmin.Browser.Nodes['exclusion_constraint'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       type: 'exclusion_constraint',
       label: gettext('Exclusion constraint'),
       collection_type: 'coll-constraints',
@@ -609,7 +610,7 @@ define('pgadmin.node.exclusion_constraint', [
       sqlCreateHelp: 'ddl-constraints.html',
       dialogHelp: url_for('help.static', {'filename': 'exclusion_constraint_dialog.html'}),
       hasSQL: true,
-      parent_type: 'table',
+      parent_type: ['table','partition'],
       canDrop: true,
       canDropCascade: true,
       hasDepends: true,
@@ -916,12 +917,22 @@ define('pgadmin.node.exclusion_constraint', [
           if (data && data.check == false)
             return true;
 
-          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [],
+            immediate_parent_table_found = false,
+            is_immediate_parent_table_partitioned = false;
           // To iterate over tree to check parent node
           while (i) {
+            // If table is partitioned table then return false
+            if (!immediate_parent_table_found && (d._type == 'table' || d._type == 'partition')) {
+              immediate_parent_table_found = true;
+              if ('is_partitioned' in d && d.is_partitioned) {
+                is_immediate_parent_table_partitioned = true;
+              }
+            }
+
             // If it is schema then allow user to create table
             if (_.indexOf(['schema'], d._type) > -1)
-              return true;
+              return !is_immediate_parent_table_partitioned;
             parents.push(d._type);
             i = t.hasParent(i) ? t.parent(i) : null;
             d = i ? t.itemData(i) : null;
@@ -930,7 +941,7 @@ define('pgadmin.node.exclusion_constraint', [
           if (_.indexOf(parents, 'catalog') > -1) {
             return false;
           } else {
-            return true;
+            return !is_immediate_parent_table_partitioned;
           }
       }
     });
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js
index 95afa3e..a4bec09 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/templates/foreign_key/js/foreign_key.js
@@ -602,6 +602,7 @@ define('pgadmin.node.foreign_key', [
   // Extend the browser's node class for foreign key node
   if (!pgBrowser.Nodes['foreign_key']) {
     pgAdmin.Browser.Nodes['foreign_key'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       type: 'foreign_key',
       label: gettext('Foreign key'),
       collection_type: 'coll-constraints',
@@ -610,7 +611,7 @@ define('pgadmin.node.foreign_key', [
       dialogHelp: url_for('help.static', {'filename': 'foreign_key_dialog.html'}),
       hasSQL: true,
       hasDepends: false,
-      parent_type: 'table',
+      parent_type: ['table','partition'],
       canDrop: true,
       canDropCascade: true,
       hasDepends: true,
@@ -1068,12 +1069,22 @@ define('pgadmin.node.foreign_key', [
           if (data && data.check == false)
             return true;
 
-          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [],
+            immediate_parent_table_found = false,
+            is_immediate_parent_table_partitioned = false;
           // To iterate over tree to check parent node
           while (i) {
+            // If table is partitioned table then return false
+            if (!immediate_parent_table_found && (d._type == 'table' || d._type == 'partition')) {
+              immediate_parent_table_found = true;
+              if ('is_partitioned' in d && d.is_partitioned) {
+                is_immediate_parent_table_partitioned = true;
+              }
+            }
+
             // If it is schema then allow user to c reate table
             if (_.indexOf(['schema'], d._type) > -1)
-              return true;
+              return !is_immediate_parent_table_partitioned;
             parents.push(d._type);
             i = t.hasParent(i) ? t.parent(i) : null;
             d = i ? t.itemData(i) : null;
@@ -1082,7 +1093,7 @@ define('pgadmin.node.foreign_key', [
           if (_.indexOf(parents, 'catalog') > -1) {
             return false;
           } else {
-            return true;
+            return !is_immediate_parent_table_partitioned;
           }
       }
     });
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
index 97a404a..9479acd 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/templates/index_constraint/js/index_constraint.js
@@ -6,6 +6,7 @@ define('pgadmin.node.{{node_type}}', [
   // Extend the browser's node class for index constraint node
   if (!pgBrowser.Nodes['{{node_type}}']) {
     pgAdmin.Browser.Nodes['{{node_type}}'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       type: '{{node_type}}',
       label: '{{ node_label }}',
       collection_type: 'coll-constraints',
@@ -20,7 +21,7 @@ define('pgadmin.node.{{node_type}}', [
       hasDepends: true,
       hasStatistics: true,
       statsPrettifyFields: ['Index size'],
-      parent_type: 'table',
+      parent_type: ['table','partition'],
       canDrop: true,
       canDropCascade: true,
       Init: function() {
@@ -45,12 +46,28 @@ define('pgadmin.node.{{node_type}}', [
         if (data && data.check == false)
           return true;
 
-        var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+        var t = pgBrowser.tree, i = item, d = itemData, parents = [],
+          immediate_parent_table_found = false,
+          is_immediate_parent_table_partitioned = false;
+
         // To iterate over tree to check parent node
         while (i) {
-          // If it is schema then allow user to c reate table
+          // If table is partitioned table then return false
+          if (!immediate_parent_table_found && (d._type == 'table' || d._type == 'partition')) {
+            immediate_parent_table_found = true;
+            if ('is_partitioned' in d && d.is_partitioned) {
+                is_immediate_parent_table_partitioned = true;
+            }
+          }
+
+          // If it is schema then allow user to create table
           if (_.indexOf(['schema'], d._type) > -1) {
             {% if node_type == 'primary_key' %}
+
+            if (is_immediate_parent_table_partitioned) {
+              return false;
+            }
+
             // There should be only one primary key per table.
             var children = t.children(arguments[1], false),
               primary_key_found = false;
@@ -63,7 +80,7 @@ define('pgadmin.node.{{node_type}}', [
             });
             return !primary_key_found;
             {% else %}
-            return true;
+            return !is_immediate_parent_table_partitioned;
             {% endif %}
           }
           parents.push(d._type);
@@ -74,7 +91,7 @@ define('pgadmin.node.{{node_type}}', [
         if (_.indexOf(parents, 'catalog') > -1) {
           return false;
         } else {
-            return true;
+            return !is_immediate_parent_table_partitioned;
         }
       },
 
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js
index a7346f1..e372b3c 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js
@@ -9,16 +9,18 @@ define('pgadmin.node.constraints', [
         node: 'constraints',
         label: gettext('Constraints'),
         type: 'coll-constraints',
+        getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
         columns: ['name', 'comment']
       });
   };
 
   if (!pgBrowser.Nodes['constraints']) {
     pgAdmin.Browser.Nodes['constraints'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       type: 'constraints',
       label: gettext('Constraints'),
       collection_type: 'coll-constraints',
-      parent_type: ['table'],
+      parent_type: ['table','partition'],
       Init: function() {
         /* Avoid mulitple registration of menus */
         if (this.initialized)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
index e52c15b..85da766 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py
@@ -72,6 +72,18 @@ class IndexesModule(CollectionNodeModule):
         if super(IndexesModule, self).BackendSupported(manager, **kwargs):
             conn = manager.connection(did=kwargs['did'])
 
+            # In case of partitioned table return false.
+            if 'tid' in kwargs and manager.version >= 100000:
+                partition_path = 'partition/sql/#{0}#'.format(manager.version)
+                SQL = render_template("/".join(
+                    [partition_path, 'backend_support.sql']), tid=kwargs['tid'])
+                status, res = conn.execute_scalar(SQL)
+
+                # check if any errors
+                if not status:
+                    return internal_server_error(errormsg=res)
+                return not res
+
             if 'vid' not in kwargs:
                 return True
 
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
index 24f37f0..4fc1d54 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/templates/index/js/index.js
@@ -10,6 +10,7 @@ define('pgadmin.node.index', [
         node: 'index',
         label: gettext('Indexes'),
         type: 'coll-index',
+        getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
         sqlAlterHelp: 'sql-alterindex.html',
         sqlCreateHelp: 'sql-createindex.html',
         dialogHelp: url_for('help.static', {'filename': 'index_dialog.html'}),
@@ -210,8 +211,9 @@ define('pgadmin.node.index', [
     });
 
   if (!pgBrowser.Nodes['index']) {
-    pgAdmin.Browser.Nodes['index'] = pgAdmin.Browser.Node.extend({
-      parent_type: ['table', 'view', 'mview'],
+    pgAdmin.Browser.Nodes['index'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
+      parent_type: ['table', 'view', 'mview', 'partition'],
       collection_type: ['coll-table', 'coll-view'],
       sqlAlterHelp: 'sql-alterindex.html',
       sqlCreateHelp: 'sql-createindex.html',
@@ -247,6 +249,12 @@ define('pgadmin.node.index', [
           icon: 'wcTabIcon icon-index', data: {action: 'create', check: true},
           enable: 'canCreate'
         },{
+          name: 'create_index_onPartition', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: gettext('Index...'),
+          icon: 'wcTabIcon icon-index', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
           name: 'create_index_onMatView', node: 'mview', module: this,
           applies: ['object', 'context'], callback: 'show_obj_properties',
           category: 'create', priority: 5, label: gettext('Index...'),
@@ -472,12 +480,23 @@ define('pgadmin.node.index', [
           if (data && data.check == false)
             return true;
 
-          var t = pgBrowser.tree, i = item, d = itemData, parents = [];
+          var t = pgBrowser.tree, i = item, d = itemData, parents = [],
+            immediate_parent_table_found = false,
+            is_immediate_parent_table_partitioned = false;
           // To iterate over tree to check parent node
           while (i) {
-            // If it is schema then allow user to c reate table
+            // Do not allow creating index on partitioned tables.
+            if (!immediate_parent_table_found &&
+                _.indexOf(['table', 'partition'], d._type) > -1) {
+              immediate_parent_table_found = true;
+              if ('is_partitioned' in d && d.is_partitioned) {
+                is_immediate_parent_table_partitioned = true;
+              }
+            }
+
+            // If it is schema then allow user to create index
             if (_.indexOf(['schema'], d._type) > -1)
-              return true;
+              return !is_immediate_parent_table_partitioned;
             parents.push(d._type);
             i = t.hasParent(i) ? t.parent(i) : null;
             d = i ? t.itemData(i) : null;
@@ -486,7 +505,7 @@ define('pgadmin.node.index', [
           if (_.indexOf(parents, 'catalog') > -1) {
             return false;
           } else {
-            return true;
+            return !is_immediate_parent_table_partitioned;
           }
       }
   });
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py
new file mode 100644
index 0000000..a1c010f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/__init__.py
@@ -0,0 +1,583 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2017, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Partitions Node """
+
+import re
+import simplejson as json
+import pgadmin.browser.server_groups.servers.databases.schemas as schema
+from flask import render_template, request
+from flask_babel import gettext
+from pgadmin.browser.server_groups.servers.databases.schemas.utils \
+    import DataTypeReader, VacuumSettings
+from pgadmin.utils.ajax import internal_server_error, \
+    make_response as ajax_response, gone
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.utils \
+    import BaseTableView
+from pgadmin.browser.collection import CollectionNodeModule
+from pgadmin.utils.ajax import make_json_response, precondition_required
+from config import PG_DEFAULT_DRIVER
+from pgadmin.browser.utils import PGChildModule
+
+
+class PartitionsModule(CollectionNodeModule):
+    """
+     class PartitionsModule(CollectionNodeModule)
+
+        A module class for Partition node derived from CollectionNodeModule.
+
+    Methods:
+    -------
+    * __init__(*args, **kwargs)
+      - Method is used to initialize the Partition and it's base module.
+
+    * get_nodes(gid, sid, did, scid, tid)
+      - Method is used to generate the browser collection node.
+
+    * node_inode()
+      - Method is overridden from its base class to make the node as leaf node.
+
+    * script_load()
+      - Load the module script for schema, when any of the server node is
+        initialized.
+    """
+
+    NODE_TYPE = 'partition'
+    COLLECTION_LABEL = gettext("Partitions")
+
+    def __init__(self, *args, **kwargs):
+        """
+        Method is used to initialize the PartitionsModule and it's base module.
+
+        Args:
+            *args:
+            **kwargs:
+        """
+        super(PartitionsModule, self).__init__(*args, **kwargs)
+        self.min_ver = 100000
+        self.max_ver = None
+
+    def get_nodes(self, gid, sid, did, scid, **kwargs):
+        """
+        Generate the collection node
+        """
+        yield self.generate_browser_collection_node(kwargs['tid'])
+
+    @property
+    def script_load(self):
+        """
+        Load the module script for server, when any of the server-group node is
+        initialized.
+        """
+        return schema.SchemaModule.NODE_TYPE
+
+    @property
+    def node_inode(self):
+        """
+        Load the module node as a leaf node
+        """
+        return True
+
+    def BackendSupported(self, manager, **kwargs):
+        """
+        Load this module if it is a partition table
+        """
+        if 'tid' in kwargs and CollectionNodeModule.BackendSupported(self, manager, **kwargs):
+            conn = manager.connection(did=kwargs['did'])
+
+            template_path = 'partition/sql/#{0}#'.format(manager.version)
+            SQL = render_template("/".join(
+                [template_path, 'backend_support.sql']), tid=kwargs['tid'])
+            status, res = conn.execute_scalar(SQL)
+
+            # check if any errors
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return res
+
+    def register(self, app, options, first_registration=False):
+        """
+        Override the default register function to automatically register
+        sub-modules of table node under partition table node.
+        """
+
+        if first_registration:
+            self.submodules = list(app.find_submodules(self.import_name))
+
+        super(CollectionNodeModule, self).register(app, options, first_registration)
+
+        for module in self.submodules:
+            if first_registration:
+                module.parentmodules.append(self)
+            app.register_blueprint(module)
+
+        # Now add sub modules of table node to partition table node.
+        if first_registration:
+            # Exclude 'partition' module for now to avoid cyclic import issue.
+            modules_to_skip = ['partition', 'column']
+            for parent in self.parentmodules:
+                if parent.NODE_TYPE == 'table':
+                    self.submodules += [
+                        submodule for submodule in parent.submodules
+                        if submodule.NODE_TYPE not in modules_to_skip
+                    ]
+
+    @property
+    def module_use_template_javascript(self):
+        """
+        Returns whether Jinja2 template is used for generating the javascript
+        module.
+        """
+        return False
+
+
+blueprint = PartitionsModule(__name__)
+
+
+class PartitionsView(BaseTableView, DataTypeReader, VacuumSettings):
+    """
+    This class is responsible for generating routes for Partition node
+
+    Methods:
+    -------
+
+    * list()
+      - This function is used to list all the Partition nodes within that
+      collection.
+
+    * nodes()
+      - This function will used to create all the child node within that
+        collection, Here it will create all the Partition node.
+
+    * properties(gid, sid, did, scid, tid, ptid)
+      - This function will show the properties of the selected Partition node
+
+    """
+
+    node_type = blueprint.node_type
+
+    parent_ids = [
+        {'type': 'int', 'id': 'gid'},
+        {'type': 'int', 'id': 'sid'},
+        {'type': 'int', 'id': 'did'},
+        {'type': 'int', 'id': 'scid'},
+        {'type': 'int', 'id': 'tid'}
+    ]
+    ids = [
+        {'type': 'int', 'id': 'ptid'}
+    ]
+
+    operations = dict({
+        'obj': [
+            {'get': 'properties', 'delete': 'delete', 'put': 'update'},
+            {'get': 'list', 'post': 'create'}
+        ],
+        'nodes': [{'get': 'nodes'}, {'get': 'nodes'}],
+        'children': [{'get': 'children'}],
+        'sql': [{'get': 'sql'}],
+        'msql': [{'get': 'msql'}, {}],
+        'detach': [{'put': 'detach'}],
+        'truncate': [{'put': 'truncate'}]
+
+    })
+
+    def children(self, **kwargs):
+        """Build a list of treeview nodes from the child nodes."""
+
+        if 'sid' not in kwargs:
+            return precondition_required(
+                gettext('Required properties are missing.')
+            )
+
+        from pgadmin.utils.driver import get_driver
+        manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
+            sid=kwargs['sid']
+        )
+
+        did = None
+        if 'did' in kwargs:
+            did = kwargs['did']
+
+        conn = manager.connection(did=did)
+
+        if not conn.connected():
+            return precondition_required(
+                gettext(
+                    "Connection to the server has been lost."
+                )
+            )
+
+        nodes = []
+        for module in self.blueprint.submodules:
+            if isinstance(module, PGChildModule):
+                if manager is not None and \
+                        module.BackendSupported(manager, **kwargs):
+                    # treat partition table as normal table.
+                    # replace tid with ptid and pop ptid from kwargs
+                    if 'ptid' in kwargs:
+                        ptid = kwargs.pop('ptid')
+                        kwargs['tid'] = ptid
+                    nodes.extend(module.get_nodes(**kwargs))
+            else:
+                nodes.extend(module.get_nodes(**kwargs))
+
+        # Explicitly include 'partition' module as we had excluded it during
+        # registration.
+        nodes.extend(self.blueprint.get_nodes(**kwargs))
+
+        # Return sorted nodes based on label
+        return make_json_response(
+            data=sorted(
+                nodes, key=lambda c: c['label']
+            )
+        )
+
+    @BaseTableView.check_precondition
+    def list(self, gid, sid, did, scid, tid):
+        """
+        This function is used to list all the table nodes within that
+        collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Table ID
+
+        Returns:
+            JSON of available table nodes
+        """
+        SQL = render_template("/".join([self.partition_template_path,
+                                        'properties.sql']),
+                              did=did, scid=scid, tid=tid,
+                              datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        return ajax_response(
+            response=res['rows'],
+            status=200
+        )
+
+    @BaseTableView.check_precondition
+    def nodes(self, gid, sid, did, scid, tid, ptid=None):
+        """
+        This function is used to list all the table nodes within that
+        collection.
+
+        Args:
+            gid: Server group ID
+            sid: Server ID
+            did: Database ID
+            scid: Schema ID
+            tid: Parent Table ID
+            ptid: Partition Table ID
+
+        Returns:
+            JSON of available table nodes
+        """
+        SQL = render_template(
+                "/".join([self.partition_template_path, 'nodes.sql']),
+                scid=scid, tid=tid
+                )
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        def browser_node(row):
+            return self.blueprint.generate_browser_node(
+                row['oid'],
+                tid,
+                row['name'],
+                icon="icon-partition",
+                tigger_count=row['triggercount'],
+                has_enable_triggers=row['has_enable_triggers'],
+                is_partitioned=row['is_partitioned'],
+                parent_schema_id=scid,
+                schema_id=row['schema_id'],
+                schema_name=row['schema_name']
+            )
+
+        if ptid is not None:
+            if len(rset['rows']) == 0:
+                return gone(gettext(
+                    "The specified partitioned table could not be found."
+                ))
+
+            return make_json_response(
+                data=browser_node(rset['rows'][0]), status=200
+                )
+
+        res = []
+        for row in rset['rows']:
+            res.append(browser_node(row))
+
+        return make_json_response(
+            data=res,
+            status=200
+        )
+
+    @BaseTableView.check_precondition
+    def properties(self, gid, sid, did, scid, tid, ptid):
+        """
+        This function will show the properties of the selected table node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did:  Database ID
+            scid: Schema ID
+            scid: Schema ID
+            tid: Table ID
+            ptid: Partition Table ID
+
+        Returns:
+            JSON of selected table node
+        """
+
+        SQL = render_template("/".join([self.partition_template_path,
+                                        'properties.sql']),
+                              did=did, scid=scid, tid=tid,
+                              ptid=ptid, datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if len(res['rows']) == 0:
+                return gone(gettext(
+                    "The specified partitioned table could not be found."))
+
+        return super(PartitionsView, self).properties(
+            gid, sid, did, scid, ptid, res)
+
+    @BaseTableView.check_precondition
+    def sql(self, gid, sid, did, scid, tid, ptid):
+        """
+        This function will creates reverse engineered sql for
+        the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           ptid: Partition Table ID
+        """
+        main_sql = []
+
+        SQL = render_template("/".join([self.partition_template_path,
+                                        'properties.sql']),
+                              did=did, scid=scid, tid=tid,
+                              ptid=ptid, datlastsysoid=self.datlastsysoid)
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        if len(res['rows']) == 0:
+                return gone(gettext(
+                    "The specified partitioned table could not be found."))
+
+        data = res['rows'][0]
+
+        return BaseTableView.get_reverse_engineered_sql(self, did, scid, ptid,
+                                                        main_sql, data)
+
+    @BaseTableView.check_precondition
+    def detach(self, gid, sid, did, scid, tid, ptid):
+        """
+        This function will reset statistics of table
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           ptid: Partition Table ID
+        """
+        # Fetch schema name
+        status, parent_schema = self.conn.execute_scalar(
+            render_template(
+                "/".join([self.table_template_path, 'get_schema.sql']),
+                conn=self.conn, scid=scid
+            )
+        )
+        if not status:
+            return internal_server_error(errormsg=parent_schema)
+
+        # Fetch Parent Table name
+        status, partitioned_table_name = self.conn.execute_scalar(
+            render_template(
+                "/".join([self.table_template_path, 'get_table.sql']),
+                conn=self.conn, scid=scid, tid=tid
+            )
+        )
+        if not status:
+            return internal_server_error(errormsg=partitioned_table_name)
+
+        # Get schema oid of partition
+        status, pscid = self.conn.execute_scalar(
+            render_template("/".join([self.table_template_path,
+                                      'get_schema_oid.sql']), tid=ptid))
+        if not status:
+            return internal_server_error(errormsg=scid)
+
+        # Fetch schema name
+        status, partition_schema = self.conn.execute_scalar(
+            render_template("/".join([self.table_template_path,
+                                      'get_schema.sql']), conn=self.conn,
+                            scid=pscid)
+        )
+        if not status:
+            return internal_server_error(errormsg=partition_schema)
+
+        # Fetch Partition Table name
+        status, partition_name = self.conn.execute_scalar(
+            render_template(
+                "/".join([self.table_template_path, 'get_table.sql']),
+                conn=self.conn, scid=pscid, tid=ptid
+            )
+        )
+        if not status:
+            return internal_server_error(errormsg=partition_name)
+
+        try:
+            temp_data = dict()
+            temp_data['parent_schema'] = parent_schema
+            temp_data['partitioned_table_name'] = partitioned_table_name
+            temp_data['schema'] = partition_schema
+            temp_data['name'] = partition_name
+
+            SQL = render_template("/".join(
+                            [self.partition_template_path, 'detach.sql']),
+                            data=temp_data, conn=self.conn)
+
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Partition detached."),
+                data={
+                    'id': ptid,
+                    'scid': scid
+                }
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @BaseTableView.check_precondition
+    def msql(self, gid, sid, did, scid, tid, ptid=None):
+        """
+        This function will create modified sql for table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        data = dict()
+        for k, v in request.args.items():
+            try:
+                data[k] = json.loads(v, encoding='utf-8')
+            except (ValueError, TypeError, KeyError):
+                data[k] = v
+
+        if ptid is not None:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+        SQL, name = self.get_sql(did, scid, ptid, data, res)
+        SQL = re.sub('\n{2,}', '\n\n', SQL)
+        SQL = SQL.strip('\n')
+        if SQL == '':
+            SQL = "--modified SQL"
+        return make_json_response(
+            data=SQL,
+            status=200
+        )
+
+    @BaseTableView.check_precondition
+    def update(self, gid, sid, did, scid, tid, ptid):
+        """
+        This function will update an existing table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           ptid: Partition Table ID
+        """
+        data = request.form if request.form else json.loads(
+            request.data, encoding='utf-8'
+        )
+
+        for k, v in data.items():
+            try:
+                data[k] = json.loads(v, encoding='utf-8')
+            except (ValueError, TypeError, KeyError):
+                data[k] = v
+
+        try:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return super(PartitionsView, self).update(
+                gid, sid, did, scid, ptid, data, res, parent_id=tid)
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    @BaseTableView.check_precondition
+    def truncate(self, gid, sid, did, scid, tid, ptid):
+        """
+        This function will truncate the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+
+        try:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  ptid=ptid, datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return super(PartitionsView, self).truncate(gid, sid, did, scid, ptid, res)
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+
+PartitionsView.register_node_view(blueprint)
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/img/coll-partition.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/img/coll-partition.png
new file mode 100644
index 0000000000000000000000000000000000000000..8536c66afb1099e1898f3c6163a709e3e5375564
GIT binary patch
literal 1433
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@6_vB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+*
zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn
zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuk*h0bFQqR!T
z(!$6@N5ROz&`jUJQs2--*TB%qz|zXVPyq^*fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj
z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5
zFD<cE0=g99h1>#PU%0_}#n6BP2AO_EVu8M)o`HUDF34YC)x{-2sR(CaRb3oXS&*t9
zlv<o$T9gcok2GbNW?<Oiw+N&V=o%~kqD)|<B<8r}Czs}?=9PH5*eU^K^incYtkTRZ
z5{*oal5`D?ObvBSOcO11lYl_iJk`X)FvY+m)g&nmW)3#}E*6d^PNt4dCN7RHhK8=@
zPHv{oF3yHVmX5}*ZjMd{Fuk66#U+V($*C~AGl6zP^*Z9!Yvo*&npl!w6q28x14{(~
z8Tlpo#Toep3eL`;ST|SD@J&q4%mWE(f+7myZ<o}f%(B!Jx1#)91#n1PWnyuKsfDSj
zMT%iE(96kbx+aOq2D+B!CaJo{7D+&<RLc}|lVl~R{uFXUP#@?heNb{iN<J_lV44Im
z;h6!*foG@GJYXIw0%n%qD-S6%FfeZSba4!+xHV_edF>WQiR1f?-$y8V26cBo;ukpW
z=+RYGK7G-gzl?l(e4Fal=E%q_nKMVmMN`v0tN7NF1u8|8pD6Kdd7GMhZQtXWmE{{H
zj~M%Yu3h%L@|p2@p3iOH%O^{U`B*nhQJ8EZ(aRtEZesQK;D2!vJ}aKMd}lkrZTQQg
z`{=361Cu0b1FGg^aZGV#Z~Ad8;^L7;pIfsXUQ4Z>W&6XJH@wmK<A$;#6VGbt!@9f`
zd~X!4PQM)O@pF5r&plCzt6OJhZ&~cew)}Hc_)V*eYtnvgHhCU#@PT#jqH`AuTGbR{
zPt;#1n0jkl%?q<5F3E)=)jE5%;<F#VTP<N2R`BW@2jh&49jXCYOAW;5vn*!vI)AzD
z*22e6RDT@m_Fwh#+fVJ@yH8vjCpW$QeCU46+gES)bqQ)|nq68v*~i4k>cN&MBj)b5
z)v^{(Ue9nkcz<KD%9p7((xr0Uue<3Uc^kPTn{}bfjkcN3(uMuA7ji~jZRvb=ovE^~
zvCX*c@n-2QzhAv@)j8s~?!wKW{x7SW`<7<ZF$$mc_x*CAJ|Sq9r*@lC@%pX33rpNs
qgTo`g&An@W?f;S|@032N9bhoZ__yrHkA@AP!qU^#&t;ucLK6VNc@r4`

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/img/partition.png b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/img/partition.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d6dd8b35ad2da1c150dcfe5be8861c73cef72e6
GIT binary patch
literal 1264
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m^Cs(B1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+*
zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn
zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxOgGuk*h0bFQqR!T
z(!$6@N5ROz&`jUJQs2--*TB%qz|zXVPyq^*fVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj
z%k|2Q_413-^$jg8E%gnI^o@*kfhu&1EAvVcD|GXUm0>2hq!uR^WfqiV=I1GZOiWD5
zFD<cE0=g99h1>$Tv3bSNU;+l1ennz|zM-B0$V)JVzP|XC=H|jx7ncO3BHWAB;Np<V
zf>iyW)Z+ZoqGVvir744~DzI`cN=+=uFAB-e&w+(vKt_H^esM;Afr7I$DAddqG<*}2
zGxI=#nqXbNzE+-j#U+V($*G<$wn{*A^fEJ3tSsFO-He>fEln(q4Gj%l%`IKbot#Xa
zOx+BPU7XC#++ccL@{>z*Q}aq-dQ%X39dYUfC5YStpv^9+MVV!(DQ-pixe8#9TV>*Q
zi#bm7pn6kqyTt;hUVWfr^g+>!6x}c(U>X83;fWW>fhYgeJYbqH0w(S^3o~jM7#QO`
zT^vIyZmkKn^>#KCu{HNx{X&7O>4DOVM_O7I8cHDoRzI2laO*W);8VKNfAC=aL;ek1
zcSWpru3Wu(^5pJ-TTiMceb3^4bSeGNUX|x}izijT?>;m4-rc&&m1WEVBAFhaPHDba
z;TY+3=vPIIt9|UXW!+ECpW;n8)^U7-UZ35$Lepxdh_;_SW(Trkrmt8$BkOH=tc_%w
z<Fyo~EuEXrep9PGvwrI1KEpksA{{Z3>+iq*c+9A$^on3a-1W{y!a6O7W<9@pyjtsn
z2#3gyjQwu5NAKOLQIZzYdHe7sul4F~k*yr}(wQvdBIBEuXDo=_7XKhAFh*xOo5ZT<
zRnqU)Rz>)&R}{@_DE1e=+VY&U&n}{QnV3+3?velfB3Va+3MT%o*ztRH@9g?5h1Dy1
zqpz?15-*yeeCgog=l<)oZ(e*Iv59G>Wrj%=xAxa{{PyQ}u9v(2rl57{`=Xjpe}BG-
bZeV0EdB614s(jTpP#NUu>gTe~DWM4f22aJ%

literal 0
HcmV?d00001

diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js
new file mode 100644
index 0000000..22de29c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/partitions/static/js/partition.js
@@ -0,0 +1,1276 @@
+define([
+    'sources/gettext', 'jquery', 'underscore', 'underscore.string', 'pgadmin',
+    'pgadmin.browser', 'backform', 'alertify', 'pgadmin.browser.collection',
+    'pgadmin.browser.table.partition.utils'
+],
+function(gettext, $, _, S, pgAdmin, pgBrowser, Backform, alertify) {
+
+  if (!pgBrowser.Nodes['coll-partition']) {
+    var databases = pgAdmin.Browser.Nodes['coll-partition'] =
+      pgAdmin.Browser.Collection.extend({
+        node: 'partition',
+        label: gettext('Partitions'),
+        getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
+        type: 'coll-partition',
+        columns: [
+          'name', 'schema', 'partition_value', 'is_partitioned', 'description'
+        ],
+        hasStatistics: true
+      });
+  };
+
+  if (!pgBrowser.Nodes['partition']) {
+    pgAdmin.Browser.Nodes['partition'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
+      parent_type: 'table',
+      collection_type: 'coll-partition',
+      type: 'partition',
+      label: gettext('Partition'),
+      hasSQL: true,
+      hasDepends: true,
+      hasStatistics: true,
+      statsPrettifyFields: ['Size', 'Indexes size', 'Table size',
+                            'Toast table size', 'Tuple length',
+                            'Dead tuple length', 'Free space'],
+      sqlAlterHelp: 'sql-altertable.html',
+      sqlCreateHelp: 'sql-createtable.html',
+      dialogHelp: '{{ url_for('help.static', filename='table_dialog.html') }}',
+      hasScriptTypes: ['create'],
+      height: '95%',
+      width: '85%',
+      Init: function() {
+        /* Avoid mulitple registration of menus */
+        if (this.initialized)
+            return;
+
+        this.initialized = true;
+
+        pgBrowser.add_menus([{
+          name: 'truncate_table', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'truncate_table',
+          category: 'Truncate', priority: 3, label: gettext('Truncate'),
+          icon: 'fa fa-eraser', enable : 'canCreate'
+        },{
+          name: 'truncate_table_cascade', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'truncate_table_cascade',
+          category: 'Truncate', priority: 3, label: gettext('Truncate Cascade'),
+          icon: 'fa fa-eraser', enable : 'canCreate'
+        },{
+          // To enable/disable all triggers for the table
+          name: 'enable_all_triggers', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'enable_triggers_on_table',
+          category: 'Trigger(s)', priority: 4, label: gettext('Enable All'),
+          icon: 'fa fa-check', enable : 'canCreate_with_trigger_enable'
+        },{
+          name: 'disable_all_triggers', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'disable_triggers_on_table',
+          category: 'Trigger(s)', priority: 4, label: gettext('Disable All'),
+          icon: 'fa fa-times', enable : 'canCreate_with_trigger_disable'
+        },{
+          name: 'reset_table_stats', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'reset_table_stats',
+          category: 'Reset', priority: 4, label: gettext('Reset Statistics'),
+          icon: 'fa fa-bar-chart', enable : 'canCreate'
+        },{
+          name: 'detach_partition', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'detach_partition',
+          priority: 2, label: gettext('Detach Partition'),
+          icon: 'fa fa-remove'
+        }
+        ]);
+      },
+      getTreeNodeHierarchy: function(i) {
+        var idx = 0,
+            res = {},
+            t = pgBrowser.tree;
+
+        do {
+          d = t.itemData(i);
+          if (
+            d._type in pgBrowser.Nodes && pgBrowser.Nodes[d._type].hasId
+          ) {
+            if (d._type == 'partition' && 'partition' in res) {
+              if (!('table' in res)) {
+                res['table'] = _.extend({}, d, {'priority': idx});
+                idx -= 1;
+              }
+            } else if (d._type == 'table') {
+              if (!('table' in res)) {
+                res['table'] = _.extend({}, d, {'priority': idx});
+                idx -= 1;
+              }
+            } else {
+              res[d._type] = _.extend({}, d, {'priority': idx});
+              idx -= 1;
+            }
+          }
+          i = t.hasParent(i) ? t.parent(i) : null;
+        } while (i);
+
+        return res;
+      },
+      generate_url: function(item, type, d, with_id, info) {
+        if (_.indexOf([
+            'stats', 'statistics', 'dependency', 'dependent', 'reset',
+            'get_relations', 'get_oftype', 'get_attach_tables'
+            ], type) == -1) {
+          return pgBrowser.Node.generate_url.apply(this, arguments);
+        }
+
+        if (type == 'statistics') {
+          type = 'stats';
+        }
+
+        info = (_.isUndefined(item) || _.isNull(item)) ?
+          info || {} : this.getTreeNodeHierarchy(item);
+
+        return S('table/%s/%s/%s/%s/%s/%s').sprintf(
+            encodeURIComponent(type), encodeURIComponent(info['server-group']._id),
+            encodeURIComponent(info['server']._id),
+            encodeURIComponent(info['database']._id),
+            encodeURIComponent(info['partition'].schema_id),
+            encodeURIComponent(info['partition']._id)
+            ).value();
+      },
+      canDrop: pgBrowser.Nodes['schema'].canChildDrop,
+      canDropCascade: pgBrowser.Nodes['schema'].canChildDrop,
+      callbacks: {
+        /* Enable trigger(s) on table */
+        enable_triggers_on_table: function(args) {
+            var params = {'enable': true };
+            this.callbacks.set_triggers.apply(this, [args, params]);
+        },
+        /* Disable trigger(s) on table */
+        disable_triggers_on_table: function(args) {
+            var params = {'enable': false };
+            this.callbacks.set_triggers.apply(this, [args, params]);
+        },
+        set_triggers: function(args, params) {
+          // This function will send request to enable or
+          // disable triggers on table level
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+          if (!d)
+            return false;
+
+          $.ajax({
+            url: obj.generate_url(i, 'set_trigger' , d, true),
+            type:'PUT',
+            data: params,
+            dataType: "json",
+            success: function(res) {
+              if (res.success == 1) {
+                alertify.success("{{ _('" + res.info + "') }}");
+                t.unload(i);
+                t.setInode(i);
+                t.deselect(i);
+                setTimeout(function() {
+                  t.select(i);
+                }, 10);
+              }
+            },
+            error: function(xhr, status, error) {
+              try {
+                var err = $.parseJSON(xhr.responseText);
+                if (err.success == 0) {
+                  alertify.error(err.errormsg);
+                }
+              } catch (e) {}
+              t.unload(i);
+            }
+          });
+        },
+        /* Truncate table */
+        truncate_table: function(args) {
+            var params = {'cascade': false };
+            this.callbacks.truncate.apply(this, [args, params]);
+        },
+        /* Truncate table with cascade */
+        truncate_table_cascade: function(args) {
+            var params = {'cascade': true };
+            this.callbacks.truncate.apply(this, [args, params]);
+        },
+        truncate: function(args, params) {
+          var input = args || {};
+          obj = this,
+          t = pgBrowser.tree,
+          i = input.item || t.selected(),
+          d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          alertify.confirm(
+            gettext('Truncate Table'),
+            S(gettext('Are you sure you want to truncate table %s?')).sprintf(d.label).value(),
+            function (e) {
+            if (e) {
+              var data = d;
+              $.ajax({
+                url: obj.generate_url(i, 'truncate' , d, true),
+                type:'PUT',
+                data: params,
+                dataType: "json",
+                success: function(res) {
+                  if (res.success == 1) {
+                    alertify.success("{{ _('" + res.info + "') }}");
+                    t.removeIcon(i);
+                    data.icon = 'icon-table';
+                    t.addIcon(i, {icon: data.icon});
+                    t.unload(i);
+                    t.setInode(i);
+                    t.deselect(i);
+                    // Fetch updated data from server
+                    setTimeout(function() {
+                      t.select(i);
+                    }, 10);
+                  }
+                },
+                error: function(xhr, status, error) {
+                  try {
+                    var err = $.parseJSON(xhr.responseText);
+                    if (err.success == 0) {
+                      alertify.error(err.errormsg);
+                    }
+                  } catch (e) {}
+                  t.unload(i);
+                }
+              });
+            }},
+            function() {}
+          );
+        },
+        reset_table_stats: function(args) {
+          var input = args || {},
+            obj = this,
+            t = pgBrowser.tree,
+            i = input.item || t.selected(),
+            d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          alertify.confirm(
+            gettext('Reset statistics'),
+            S(gettext('Are you sure you want to reset the statistics for table %s?')).sprintf(d._label).value(),
+            function (e) {
+              if (e) {
+                var data = d;
+                $.ajax({
+                  url: obj.generate_url(i, 'reset' , d, true),
+                  type:'DELETE',
+                  success: function(res) {
+                    if (res.success == 1) {
+                      alertify.success("{{ _('" + res.info + "') }}");
+                      t.removeIcon(i);
+                      data.icon = 'icon-table';
+                      t.addIcon(i, {icon: data.icon});
+                      t.unload(i);
+                      t.setInode(i);
+                      t.deselect(i);
+                      // Fetch updated data from server
+                      setTimeout(function() {
+                        t.select(i);
+                      }, 10);
+                    }
+                  },
+                  error: function(xhr, status, error) {
+                    try {
+                      var err = $.parseJSON(xhr.responseText);
+                      if (err.success == 0) {
+                        alertify.error(err.errormsg);
+                      }
+                    } catch (e) {}
+                    t.unload(i);
+                  }
+                });
+              }
+            },
+            function() {}
+          );
+        },
+        detach_partition: function(args) {
+          var input = args || {},
+            obj = this,
+            t = pgBrowser.tree,
+            i = input.item || t.selected(),
+            d = i && i.length == 1 ? t.itemData(i) : undefined;
+
+          if (!d)
+            return false;
+
+          alertify.confirm(
+            gettext('Detach Partition'),
+            S(gettext('Are you sure you want to detach the partition %s?')).sprintf(d._label).value(),
+            function (e) {
+              if (e) {
+                var data = d;
+                $.ajax({
+                  url: obj.generate_url(i, 'detach' , d, true),
+                  type:'PUT',
+                  success: function(res) {
+                    if (res.success == 1) {
+                      alertify.success("{{ _('" + res.info + "') }}");
+                      var n = t.next(i);
+                      if (!n || !n.length) {
+                        n = t.prev(i);
+                        if (!n || !n.length) {
+                          n = t.parent(i);
+                          t.setInode(n, true);
+                        }
+                      }
+                      t.remove(i);
+                      if (n.length) {
+                        t.select(n);
+                      }
+                    }
+                  },
+                  error: function(xhr, status, error) {
+                    try {
+                      var err = $.parseJSON(xhr.responseText);
+                      if (err.success == 0) {
+                        alertify.error(err.errormsg);
+                      }
+                    } catch (e) {}
+                  }
+                });
+              }
+            },
+            function() {}
+          );
+       }
+      },
+      model: pgBrowser.Node.Model.extend({
+        defaults: {
+          name: undefined,
+          oid: undefined,
+          spcoid: undefined,
+          spcname: undefined,
+          relowner: undefined,
+          relacl: undefined,
+          relhasoids: undefined,
+          relhassubclass: undefined,
+          reltuples: undefined,
+          description: undefined,
+          conname: undefined,
+          conkey: undefined,
+          isrepl: undefined,
+          triggercount: undefined,
+          relpersistence: undefined,
+          fillfactor: undefined,
+          reloftype: undefined,
+          typname: undefined,
+          labels: undefined,
+          providers: undefined,
+          is_sys_table: undefined,
+          coll_inherits: [],
+          hastoasttable: true,
+          toast_autovacuum_enabled: false,
+          autovacuum_enabled: false,
+          primary_key: [],
+          partitions: [],
+          partition_type: 'range',
+          is_partitioned: false,
+          partition_value: undefined
+        },
+        // Default values!
+        initialize: function(attrs, args) {
+          var self = this;
+
+          if (_.size(attrs) === 0) {
+            var userInfo = pgBrowser.serverInfo[args.node_info.server._id].user,
+                schemaInfo = args.node_info.schema;
+
+            this.set({
+              'relowner': userInfo.name, 'schema': schemaInfo._label
+            }, {silent: true});
+          }
+          pgBrowser.Node.Model.prototype.initialize.apply(this, arguments);
+
+        },
+        schema: [{
+          id: 'name', label: gettext('Name'), type: 'text',
+          mode: ['properties', 'create', 'edit'], disabled: 'inSchema'
+        },{
+          id: 'oid', label: gettext('OID'), type: 'text', mode: ['properties']
+        },{
+          id: 'relowner', label: gettext('Owner'), type: 'text', node: 'role',
+          mode: ['properties', 'create', 'edit'], select2: {allowClear: false},
+          disabled: 'inSchema', control: 'node-list-by-name'
+        },{
+          id: 'schema', label: gettext('Schema'), type: 'text', node: 'schema',
+          control: 'node-list-by-name', mode: ['create', 'edit', 'properties'],
+          disabled: 'inSchema', filter: function(d) {
+            // If schema name start with pg_* then we need to exclude them
+            if(d && d.label.match(/^pg_/))
+            {
+              return false;
+            }
+            return true;
+          }, cache_node: 'database', cache_level: 'database'
+        },{
+          id: 'spcname', label: gettext('Tablespace'), node: 'tablespace',
+          type: 'text', control: 'node-list-by-name', disabled: 'inSchema',
+          mode: ['properties', 'create', 'edit'],
+          filter: function(d) {
+            // If tablespace name is not "pg_global" then we need to exclude them
+            return (!(d && d.label.match(/pg_global/)))
+          }
+        },{
+          id: 'partition', type: 'group', label: gettext('Partition'),
+          mode: ['edit', 'create'], min_version: 100000,
+          visible: function(m) {
+            // Always show in case of create mode
+            if (m.isNew() || m.get('is_partitioned'))
+              return true;
+            return false;
+          }
+        },{
+          id: 'is_partitioned', label:gettext('Partitioned Table?'), cell: 'switch',
+          type: 'switch', mode: ['properties', 'create', 'edit'],
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (!m.isNew())
+              return true;
+            return false;
+          }
+        },{
+          id: 'description', label: gettext('Comment'), type: 'multiline',
+          mode: ['properties', 'create', 'edit'], disabled: 'inSchema'
+        },
+        {
+          id: 'partition_value', label:gettext('Partition Scheme'),
+          type: 'text', visible: false
+        },{
+          id: 'coll_inherits', label: gettext('Inherited from table(s)'),
+          type: 'text', group: gettext('Advanced'), mode: ['properties']
+        },{
+          id: 'Columns', type: 'group', label: gettext('Columns'),
+          mode: ['edit', 'create'], min_version: 100000,
+          visible: function(m) {
+            // Always hide in case of partition table.
+            return false;
+          }
+        },{
+          // Tab control for columns
+          id: 'columns', label: gettext('Columns'), type: 'collection',
+          group: gettext('Columns'),
+          model: pgBrowser.Nodes['column'].model,
+          subnode: pgBrowser.Nodes['column'].model,
+          mode: ['create', 'edit'],
+          disabled: function(m) {
+            // In case of partitioned table remove inherited columns
+            if (m.isNew() && m.get('is_partitioned')) {
+              setTimeout(function() {
+                var coll = m.get('columns');
+                coll.remove(coll.filter(function(model) {
+                  if (_.isUndefined(model.get('inheritedfrom')))
+                    return false;
+                  return true;
+                }));
+              }, 10);
+            }
+
+            if(this.node_info &&  'catalog' in this.node_info)
+            {
+              return true;
+            }
+            return false;
+          },
+          deps: ['typname', 'is_partitioned'],
+          canAdd: 'check_grid_add_condition',
+          canEdit: true, canDelete: true,
+          // For each row edit/delete button enable/disable
+          canEditRow: 'check_grid_row_edit_delete',
+          canDeleteRow: 'check_grid_row_edit_delete',
+          uniqueCol : ['name'],
+          columns : ['name' , 'cltype', 'attlen', 'attprecision', 'attnotnull', 'is_primary_key'],
+          control: Backform.UniqueColCollectionControl.extend({
+            initialize: function() {
+              Backform.UniqueColCollectionControl.prototype.initialize.apply(this, arguments);
+              var self = this,
+                  collection = self.model.get(self.field.get('name'));
+
+              collection.on("change:is_primary_key", function(m) {
+                var primary_key_coll = self.model.get('primary_key'),
+                    column_name = m.get('name'),
+                    primary_key;
+
+                if(m.get('is_primary_key')) {
+                // Add column to primary key.
+                  if (primary_key_coll.length < 1) {
+                    primary_key = new (primary_key_coll.model)({}, {
+                      top: self.model,
+                      collection: primary_key_coll,
+                      handler: primary_key_coll
+                    });
+                    primary_key_coll.add(primary_key);
+                  } else {
+                    primary_key = primary_key_coll.first();
+                  }
+                  // Do not alter existing primary key columns.
+                  if (_.isUndefined(primary_key.get('oid'))) {
+                    var primary_key_column_coll = primary_key.get('columns'),
+                      primary_key_column_exist = primary_key_column_coll.where({column:column_name});
+
+                    if (primary_key_column_exist.length == 0) {
+                      var primary_key_column = new (primary_key_column_coll.model)(
+                          {column: column_name}, { silent: true,
+                          top: self.model,
+                          collection: primary_key_coll,
+                          handler: primary_key_coll
+                        });
+
+                      primary_key_column_coll.add(primary_key_column);
+                    }
+
+                    primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
+                  }
+
+                } else {
+                // remove column from primary key.
+                  if (primary_key_coll.length > 0) {
+                    var primary_key = primary_key_coll.first();
+                    // Do not alter existing primary key columns.
+                    if (!_.isUndefined(primary_key.get('oid'))) {
+                      return;
+                    }
+
+                    var  primary_key_column_coll = primary_key.get('columns'),
+                        removedCols = primary_key_column_coll.where({column:column_name});
+                    if (removedCols.length > 0) {
+                      primary_key_column_coll.remove(removedCols);
+                      _.each(removedCols, function(m) {
+                        m.destroy();
+                      })
+                      if (primary_key_column_coll.length == 0) {
+                        setTimeout(function () {
+                          // There will be only on primary key so remove the first one.
+                          primary_key_coll.remove(primary_key_coll.first());
+                          /* Ideally above line of code should be "primary_key_coll.reset()".
+                           * But our custom DataCollection (extended from Backbone collection in datamodel.js)
+                           * does not respond to reset event, it only supports add, remove, change events.
+                           * And hence no custom event listeners/validators get called for reset event.
+                           */
+                        }, 10);
+                      }
+                    }
+                    primary_key_column_coll.trigger('pgadmin:multicolumn:updated', primary_key_column_coll);
+                  }
+                }
+              })
+            },
+            remove: function() {
+              var collection = this.model.get(this.field.get('name'));
+              if (collection) {
+                collection.off("change:is_primary_key");
+              }
+
+              Backform.UniqueColCollectionControl.prototype.remove.apply(this, arguments);
+            }
+          }),
+          allowMultipleEmptyRow: false
+        },{
+          id: 'inherited_tables_cnt', label: gettext('Inherited tables count'),
+          type: 'text', mode: ['properties'], group: gettext('Advanced'),
+          disabled: 'inSchema'
+        },{
+          // Here we will create tab control for constraints
+          type: 'nested', control: 'tab', group: gettext('Constraints'),
+          mode: ['edit', 'create'],
+          schema: [{
+              id: 'primary_key', label: gettext('Primary key'),
+              model: pgBrowser.Nodes['primary_key'].model,
+              subnode: pgBrowser.Nodes['primary_key'].model,
+              editable: false, type: 'collection',
+              group: gettext('Primary Key'), mode: ['edit', 'create'],
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
+              control: 'unique-col-collection',
+              columns : ['name', 'columns'],
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('primary_key');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
+              canAddRow: function(m) {
+               // User can only add one primary key
+               var columns = m.get('columns');
+
+               return (m.get('primary_key') &&
+                        m.get('primary_key').length < 1 &&
+                        _.some(columns.pluck('name')));
+              }
+            },{
+              id: 'foreign_key', label: gettext('Foreign key'),
+              model: pgBrowser.Nodes['foreign_key'].model,
+              subnode: pgBrowser.Nodes['foreign_key'].model,
+              editable: false, type: 'collection',
+              group: gettext('Foreign Key'), mode: ['edit', 'create'],
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
+              control: 'unique-col-collection',
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('foreign_key');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
+              columns : ['name', 'columns'],
+              canAddRow: function(m) {
+               // User can only add if there is at least one column with name.
+               var columns = m.get('columns');
+               return _.some(columns.pluck('name'));
+              }
+            },{
+              id: 'check_constraint', label: gettext('Check constraint'),
+              model: pgBrowser.Nodes['check_constraints'].model,
+              subnode: pgBrowser.Nodes['check_constraints'].model,
+              editable: false, type: 'collection',
+              group: gettext('Check'), mode: ['edit', 'create'],
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
+              control: 'unique-col-collection',
+              canAdd: true,
+              columns : ['name', 'consrc']
+            },{
+              id: 'unique_constraint', label: gettext('Unique Constraint'),
+              model: pgBrowser.Nodes['unique_constraint'].model,
+              subnode: pgBrowser.Nodes['unique_constraint'].model,
+              editable: false, type: 'collection',
+              group: gettext('Unique'), mode: ['edit', 'create'],
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
+              control: 'unique-col-collection',
+              columns : ['name', 'columns'],
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('unique_constraint');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
+              canAddRow: function(m) {
+               // User can only add if there is at least one column with name.
+               var columns = m.get('columns');
+               return _.some(columns.pluck('name'));
+              }
+            },{
+              id: 'exclude_constraint', label: gettext('Exclude constraint'),
+              model: pgBrowser.Nodes['exclusion_constraint'].model,
+              subnode: pgBrowser.Nodes['exclusion_constraint'].model,
+              editable: false, type: 'collection',
+              group: gettext('Exclude'), mode: ['edit', 'create'],
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
+              control: 'unique-col-collection',
+              columns : ['name', 'columns', 'constraint'],
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('exclude_constraint');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
+              canAddRow: function(m) {
+               // User can only add if there is at least one column with name.
+               var columns = m.get('columns');
+               return _.some(columns.pluck('name'));
+              }
+          }]
+        },{
+          id: 'typname', label: gettext('Of type'), type: 'text',
+          control: 'node-ajax-options', mode: ['properties', 'create', 'edit'],
+          disabled: 'checkOfType', url: 'get_oftype', group: gettext('Advanced'),
+          deps: ['coll_inherits', 'is_partitioned'], transform: function(data, cell) {
+            var control = cell || this,
+              m = control.model;
+              m.of_types_tables = data;
+              return data;
+          },
+          control: Backform.NodeAjaxOptionsControl.extend({
+              // When of_types changes we need to clear columns collection
+              onChange: function() {
+                Backform.NodeAjaxOptionsControl.prototype.onChange.apply(this, arguments);
+                var self = this,
+                  tbl_oid = undefined,
+                  tbl_name = self.model.get('typname'),
+                  data = undefined,
+                  arg = undefined,
+                  column_collection = self.model.get('columns');
+
+                if (!_.isUndefined(tbl_name) &&
+                    tbl_name !== '' && column_collection.length !== 0) {
+                  var msg = gettext('Changing of type table will clear columns collection');
+                  alertify.confirm(msg, function (e) {
+                    if (e) {
+                      // User clicks Ok, lets clear columns collection
+                      column_collection.reset();
+                    } else {
+                      return this;
+                    }
+                  });
+                } else if (!_.isUndefined(tbl_name) && tbl_name === '') {
+                  column_collection.reset();
+                }
+
+                // Run Ajax now to fetch columns
+                if (!_.isUndefined(tbl_name) && tbl_name !== '') {
+                  arg = { 'tname': tbl_name }
+                  data = self.model.fetch_columns_ajax.apply(self, [arg]);
+                  // Add into column collection
+                  column_collection.set(data, { merge:false,remove:false });
+                }
+              }
+            })
+        },{
+          id: 'fillfactor', label: gettext('Fill factor'), type: 'int',
+          mode: ['create', 'edit'], min: 10, max: 100,
+          disabled: 'inSchema',group: gettext('Advanced')
+        },{
+          id: 'relhasoids', label: gettext('Has OIDs?'), cell: 'switch',
+          type: 'switch', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchema', group: gettext('Advanced')
+        },{
+          id: 'relpersistence', label: gettext('Unlogged?'), cell: 'switch',
+          type: 'switch', mode: ['properties', 'create', 'edit'],
+          disabled: 'inSchemaWithModelCheck',
+          group: gettext('Advanced')
+        },{
+          id: 'conname', label: gettext('Primary key'), cell: 'string',
+          type: 'text', mode: ['properties'], group: gettext('Advanced'),
+          disabled: 'inSchema'
+        },{
+          id: 'reltuples', label: gettext('Rows (estimated)'), cell: 'string',
+          type: 'text', mode: ['properties'], group: gettext('Advanced'),
+          disabled: 'inSchema'
+        },{
+          id: 'rows_cnt', label: gettext('Rows (counted)'), cell: 'string',
+          type: 'text', mode: ['properties'], group: gettext('Advanced'),
+          disabled: 'inSchema'
+        },{
+          id: 'relhassubclass', label: gettext('Inherits tables?'), cell: 'switch',
+          type: 'switch', mode: ['properties'], group: gettext('Advanced'),
+          disabled: 'inSchema'
+        },{
+          id: 'is_sys_table', label: gettext('System table?'), cell: 'switch',
+          type: 'switch', mode: ['properties'],
+          disabled: 'inSchema'
+        },{
+          type: 'nested', control: 'fieldset', label: gettext('Like'),
+          group: gettext('Advanced'),
+          schema:[{
+            id: 'like_relation', label: gettext('Relation'),
+            type: 'text', mode: ['create', 'edit'], deps: ['typname'],
+            control: 'node-ajax-options', url: 'get_relations',
+            disabled: 'isLikeDisable', group: gettext('Like')
+          },{
+            id: 'like_default_value', label: gettext('With default values?'),
+            type: 'switch', mode: ['create', 'edit'], deps: ['typname'],
+            disabled: 'isLikeDisable', group: gettext('Like')
+          },{
+            id: 'like_constraints', label: gettext('With constraints?'),
+            type: 'switch', mode: ['create', 'edit'], deps: ['typname'],
+            disabled: 'isLikeDisable', group: gettext('Like')
+          },{
+            id: 'like_indexes', label: gettext('With indexes?'),
+            type: 'switch', mode: ['create', 'edit'], deps: ['typname'],
+            disabled: 'isLikeDisable', group: gettext('Like')
+          },{
+            id: 'like_storage', label: gettext('With storage?'),
+            type: 'switch', mode: ['create', 'edit'], deps: ['typname'],
+            disabled: 'isLikeDisable', group: gettext('Like')
+          },{
+            id: 'like_comments', label: gettext('With comments?'),
+            type: 'switch', mode: ['create', 'edit'], deps: ['typname'],
+            disabled: 'isLikeDisable', group: gettext('Like')
+          }]
+        },{
+          id: 'partition_type', label:gettext('Partition Type'),
+          editable: false, type: 'select2', select2: {allowClear: false},
+          group: 'partition', deps: ['is_partitioned'],
+          options:[{
+            label: 'Range', value: 'range'
+          },{
+            label: 'List', value: 'list'
+          }],
+          mode:['create'],
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (!m.isNew() || !m.get('is_partitioned'))
+              return true;
+            return false;
+          }
+        },{
+          id: 'partition_keys', label:gettext('Partition Keys'),
+          model: Backform.PartitionKeyModel,
+          subnode: Backform.PartitionKeyModel,
+          editable: true, type: 'collection',
+          group: 'partition', mode: ['create'],
+          deps: ['is_partitioned', 'partition_type'],
+          canEdit: false, canDelete: true,
+          control: 'sub-node-collection',
+          canAdd: function(m) {
+            if (m.isNew() && m.get('is_partitioned'))
+              return true;
+            return false;
+          },
+          canAddRow: function(m) {
+            var columns = m.get('columns');
+            var max_row_count = 1000;
+
+            if (m.get('partition_type') && m.get('partition_type') == 'list')
+              max_row_count = 1;
+
+            return (m.get('partition_keys') &&
+                m.get('partition_keys').length < max_row_count &&
+                _.some(columns.pluck('name'))
+            );
+          },
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (m.get('partition_keys') && m.get('partition_keys').models.length > 0) {
+              setTimeout(function () {
+                var coll = m.get('partition_keys');
+                coll.remove(coll.filter(function(model) {
+                  return true;
+                }));
+              }, 10);
+            }
+          }
+        },{
+          id: 'partition_scheme', label: gettext('Partition Scheme'),
+          type: 'note', group: 'partition', mode: ['edit'],
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (!m.isNew()) {
+              this.text = m.get('partition_scheme');
+            }
+          }
+        },{
+          id: 'partitions', label:gettext('Partitions'),
+          model: Backform.PartitionsModel,
+          subnode: Backform.PartitionsModel,
+          editable: true, type: 'collection',
+          group: 'partition', mode: ['edit', 'create'],
+          deps: ['is_partitioned', 'partition_type'],
+          canEdit: false, canDelete: true,
+          customDeleteTitle: gettext('Detach Partition'),
+          customDeleteMsg: gettext('Are you sure you wish to detach this partition?'),
+          columns:['is_attach', 'partition_name', 'values_from', 'values_to', 'values_in'],
+          control: Backform.SubNodeCollectionControl.extend({
+            row: Backgrid.PartitionRow,
+            initialize: function() {
+              Backform.SubNodeCollectionControl.prototype.initialize.apply(this, arguments);
+              var self = this;
+              if (!this.model.isNew()) {
+                var node = this.field.get('schema_node'),
+                    node_info = this.field.get('node_info');
+
+                // Make ajax call to get the tables to be attached
+                $.ajax({
+                  url: node.generate_url.apply(
+                      node, [
+                        null, 'get_attach_tables', this.field.get('node_data'),
+                        true, node_info
+                      ]),
+
+                  type: 'GET',
+                  async: false,
+                  success: function(res) {
+                    if (res.success == 1) {
+                      self.model.table_options = res.data;
+                    }
+                    else {
+                      alertify.alert(
+                        'Error fetching tables to be attached', res.data.result
+                      );
+                    }
+                  },
+                  error: function(e) {
+                    var errmsg = $.parseJSON(e.responseText);
+                    alertify.alert('Error fetching tables to be attached.', errmsg.errormsg);
+                  }
+                });
+              }
+            }
+          }
+          ),
+          canAdd: function(m) {
+            if (m.get('is_partitioned'))
+              return true;
+            return false;
+          },
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (m.isNew() && m.get('partitions') && m.get('partitions').models.length > 0) {
+              setTimeout(function () {
+                var coll = m.get('partitions');
+                coll.remove(coll.filter(function(model) {
+                  return true;
+                }));
+              }, 10);
+            }
+          }
+        },{
+          id: 'partition_note', label: gettext('Partition'),
+          type: 'note', group: 'partition',
+          text: gettext('Above control will be used to Create/Attach/Detach partitions.<br>' +
+            '<ul><li>Create Mode: User will be able to create N number of partitions. Mode switch control is disabled in this scenario.</li>' +
+            '<li>Edit Mode: User will be able to create/attach/detach N number of partitions.' +
+            'In attach mode there will be list of suitable tables to be attached.</li></ul>'),
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          }
+        },{
+          // Here - we will create tab control for storage parameters
+          // (auto vacuum).
+          type: 'nested', control: 'tab', group: gettext('Parameter'),
+          mode: ['edit', 'create'], deps: ['is_partitioned'],
+          schema: Backform.VacuumSettingsSchema
+        },{
+          id: 'relacl_str', label: gettext('Privileges'), disabled: 'inSchema',
+          type: 'text', mode: ['properties'], group: gettext('Security')
+        }, pgBrowser.SecurityGroupUnderSchema,{
+          id: 'relacl', label: gettext('Privileges'), type: 'collection',
+          group: 'security', control: 'unique-col-collection',
+          model: pgBrowser.Node.PrivilegeRoleModel.extend({
+          privileges: ['a','r','w','d','D','x','t']}),
+          mode: ['edit', 'create'], canAdd: true, canDelete: true,
+          uniqueCol : ['grantee']
+        },{
+          id: 'seclabels', label: gettext('Security labels'), canEdit: false,
+          model: pgBrowser.SecLabelModel, editable: false, canAdd: true,
+          type: 'collection', min_version: 90100, mode: ['edit', 'create'],
+          group: 'security', canDelete: true, control: 'unique-col-collection'
+        },{
+          id: 'vacuum_settings_str', label: gettext('Storage settings'),
+          type: 'multiline', group: gettext('Advanced'), mode: ['properties']
+        }],
+        validate: function(keys) {
+          var err = {},
+              changedAttrs = this.changed,
+              msg = undefined,
+              name = this.get('name'),
+              schema = this.get('schema'),
+              relowner = this.get('relowner'),
+              is_partitioned = this.get('is_partitioned'),
+              partition_keys = this.get('partition_keys');
+
+          // If nothing to validate or VacuumSetting keys then
+          // return from here
+          if ( keys && (keys.length == 0
+                        || _.indexOf(keys, 'autovacuum_enabled') != -1
+                        || _.indexOf(keys, 'toast_autovacuum_enabled') != -1) ) {
+            return null;
+          }
+
+          // Have to clear existing validation before initiating current state validation only
+          this.errorModel.clear();
+
+          if (_.isUndefined(name) || _.isNull(name) ||
+            String(name).replace(/^\s+|\s+$/g, '') == '') {
+            msg = gettext('Table name cannot be empty.');
+            this.errorModel.set('name', msg);
+            return msg;
+          } else if (_.isUndefined(schema) || _.isNull(schema) ||
+            String(schema).replace(/^\s+|\s+$/g, '') == '') {
+            msg = gettext('Table schema cannot be empty.');
+            this.errorModel.set('schema', msg);
+            return msg;
+          } else if (_.isUndefined(relowner) || _.isNull(relowner) ||
+            String(relowner).replace(/^\s+|\s+$/g, '') == '') {
+            msg = gettext('Table owner cannot be empty.');
+            this.errorModel.set('relowner', msg);
+            return msg;
+          } else if (is_partitioned && this.isNew() &&
+            !_.isNull(partition_keys) && partition_keys.length <= 0)
+          {
+            msg = gettext('Please specify at least one key for partitioned table.');
+            this.errorModel.set('partition_keys', msg);
+            return msg;
+          }
+          return null;
+        },
+        // We will disable everything if we are under catalog node
+        inSchema: function() {
+          if(this.node_info &&  'catalog' in this.node_info)
+          {
+            return true;
+          }
+          return false;
+        },
+        isInheritedTable: function(m) {
+          if(!m.inSchema.apply(this, [m])) {
+            if(
+              (!_.isUndefined(m.get('coll_inherits')) && m.get('coll_inherits').length != 0)
+                ||
+                  (!_.isUndefined(m.get('typname')) && String(m.get('typname')).replace(/^\s+|\s+$/g, '') !== '')
+            ) {
+              // Either of_types or coll_inherits has value
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return false;
+        },
+        // Oftype is defined?
+        checkInheritance: function(m) {
+          // Disabled if it is partitioned table
+          if (m.get('is_partitioned')) {
+            setTimeout( function() {
+               m.set('coll_inherits', []);
+            }, 10);
+            return true;
+          }
+
+          // coll_inherits || typname
+          if(!m.inSchema.apply(this, [m]) &&
+              ( _.isUndefined(m.get('typname')) ||
+                _.isNull(m.get('typname')) ||
+                String(m.get('typname')).replace(/^\s+|\s+$/g, '') == '')) {
+            return false;
+          }
+          return true;
+        },
+        // We will disable Like if ofType is defined
+        isLikeDisable: function(m) {
+          if(!m.inSchemaWithModelCheck.apply(this, [m]) &&
+              ( _.isUndefined(m.get('typname')) ||
+                _.isNull(m.get('typname')) ||
+                String(m.get('typname')).replace(/^\s+|\s+$/g, '') == '')) {
+            return false;
+          }
+          return true;
+        },
+        // Check for column grid when to Add
+        check_grid_add_condition: function(m) {
+          var enable_flag = true;
+          if(!m.inSchema.apply(this, [m])) {
+            // if of_type then disable add in grid
+            if (!_.isUndefined(m.get('typname')) &&
+                !_.isNull(m.get('typname')) &&
+                m.get('typname') !== '') {
+                    enable_flag = false;
+                }
+          }
+          return enable_flag;
+        },
+        // Check for column grid when to edit/delete (for each row)
+        check_grid_row_edit_delete: function(m) {
+          var flag = true;
+          if(!_.isUndefined(m.get('inheritedfrom')) &&
+               !_.isNull(m.get('inheritedfrom')) &&
+               String(m.get('inheritedfrom')).replace(/^\s+|\s+$/g, '') !== '') {
+            flag = false;
+          }
+          return flag;
+        },
+        // We will disable it if Inheritance is defined
+        checkOfType: function(m) {
+          // Disabled if it is partitioned table
+          if (m.get('is_partitioned')) {
+            setTimeout( function() {
+               m.set('typname', undefined);
+            }, 10);
+            return true;
+          }
+
+          //coll_inherits || typname
+          if(!m.inSchemaWithModelCheck.apply(this, [m]) &&
+              (_.isUndefined(m.get('coll_inherits')) ||
+               _.isNull(m.get('coll_inherits')) ||
+               String(m.get('coll_inherits')).replace(/^\s+|\s+$/g, '') == '')) {
+            return false;
+          }
+          return true;
+        },
+        // We will check if we are under schema node & in 'create' mode
+        inSchemaWithModelCheck: function(m) {
+          if(this.node_info &&  'schema' in this.node_info)
+          {
+            // We will disbale control if it's in 'edit' mode
+            if (m.isNew()) {
+              return false;
+            } else {
+              return true;
+            }
+          }
+          return true;
+        },
+        isTableAutoVacuumEnable: function(m) {
+          // We need to check additional condition to toggle enable/disable
+          // for table auto-vacuum
+          if(!m.inSchema.apply(this, [m]) &&
+              m.get('autovacuum_enabled') === true) {
+            return false;
+          }
+          return true;
+        },
+        isToastTableAutoVacuumEnable: function(m) {
+          // We need to check additional condition to toggle enable/disable
+          // for toast table auto-vacuum
+          if(!m.inSchemaWithModelCheck.apply(this, [m]) &&
+              m.get('toast_autovacuum_enabled') == true) {
+            return false;
+          }
+          return true;
+        },
+        fetch_columns_ajax: function(arg) {
+          var self = this,
+              url = 'get_columns',
+              m = self.model.top || self.model,
+              old_columns = _.clone(m.get('columns'))
+              data = undefined,
+              node = this.field.get('schema_node'),
+              node_info = this.field.get('node_info'),
+              full_url = node.generate_url.apply(
+                node, [
+                  null, url, this.field.get('node_data'),
+                  this.field.get('url_with_id') || false, node_info
+                ]
+              ),
+              cache_level = this.field.get('cache_level') || node.type,
+              cache_node = this.field.get('cache_node');
+
+          cache_node = (cache_node && pgBrowser.Nodes['cache_node']) || node;
+
+          m.trigger('pgadmin:view:fetching', m, self.field);
+          // Fetching Columns data for the selected table.
+          $.ajax({
+            async: false,
+            url: full_url,
+            data: arg,
+            success: function(res) {
+              data = cache_node.cache(url, node_info, cache_level, res.data);
+            },
+            error: function() {
+              m.trigger('pgadmin:view:fetch:error', m, self.field);
+            }
+          });
+          m.trigger('pgadmin:view:fetched', m, self.field);
+          data = (data && data.data) || [];
+          return data;
+        }
+      }),
+      canCreate: function(itemData, item, data) {
+          //If check is false then , we will allow create menu
+          if (data && data.check == false)
+            return true;
+
+          var t = pgBrowser.tree, i = item, d = itemData;
+          // To iterate over tree to check parent node
+          while (i) {
+            // If it is schema then allow user to create table
+            if (_.indexOf(['schema'], d._type) > -1)
+              return true;
+
+            if ('coll-table' == d._type) {
+              //Check if we are not child of catalog
+              prev_i = t.hasParent(i) ? t.parent(i) : null;
+              prev_d = prev_i ? t.itemData(prev_i) : null;
+              if( prev_d._type == 'catalog') {
+                return false;
+              } else {
+                return true;
+              }
+            }
+            i = t.hasParent(i) ? t.parent(i) : null;
+            d = i ? t.itemData(i) : null;
+          }
+          // by default we do not want to allow create menu
+          return true;
+      },
+      // Check to whether table has disable trigger(s)
+      canCreate_with_trigger_enable: function(itemData, item, data) {
+        if(this.canCreate.apply(this, [itemData, item, data])) {
+          // We are here means we can create menu, now let's check condition
+          if(itemData.tigger_count > 0) {
+            return true;
+          } else {
+            return false;
+          }
+        }
+      },
+      // Check to whether table has enable trigger(s)
+      canCreate_with_trigger_disable: function(itemData, item, data) {
+        if(this.canCreate.apply(this, [itemData, item, data])) {
+          // We are here means we can create menu, now let's check condition
+          if(itemData.tigger_count > 0 && itemData.has_enable_triggers > 0) {
+            return true;
+          } else {
+            return false;
+          }
+        }
+      }
+    });
+  }
+
+  return pgBrowser.Nodes['partition'];
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js
index 25fe963..db91af3 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/templates/rules/js/rules.js
@@ -16,6 +16,7 @@ define('pgadmin.node.rule', [
         node: 'rule',
         label: gettext('Rules'),
         type: 'coll-rule',
+        getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
         columns: ["name", "owner", "comment"]
       });
   }
@@ -33,8 +34,9 @@ define('pgadmin.node.rule', [
     rule option in the context menu
    */
   if (!pgBrowser.Nodes['rule']) {
-    pgAdmin.Browser.Nodes['rule'] = pgAdmin.Browser.Node.extend({
-      parent_type: ['table','view'],
+    pgAdmin.Browser.Nodes['rule'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
+      parent_type: ['table','view', 'partition'],
       type: 'rule',
       sqlAlterHelp: 'sql-alterrule.html',
       sqlCreateHelp: 'sql-createrule.html',
@@ -98,6 +100,12 @@ define('pgadmin.node.rule', [
           category: 'create', priority: 4, label: gettext('Rule...'),
           icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
           enable: 'canCreate'
+        },{
+          name: 'create_rule', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: gettext('Rule...'),
+          icon: 'wcTabIcon icon-rule', data: {action: 'create', check: true},
+          enable: 'canCreate'
         }
         ]);
       },
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.js
new file mode 100644
index 0000000..5b1e3c1
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/partition.utils.js
@@ -0,0 +1,323 @@
+define(
+        ['sources/gettext', 'jquery', 'underscore', 'pgadmin.browser',
+        'backform','backgrid', 'pgadmin.browser.collection'],
+function(gettext, $, _, pgBrowser, Backform, Backgrid) {
+
+  Backgrid.PartitionRow = Backgrid.Row.extend({
+    modelDuplicateColor: "lightYellow",
+
+    modelUniqueColor: "#fff",
+
+    initialize: function () {
+      Backgrid.Row.prototype.initialize.apply(this, arguments);
+      var self = this;
+      self.model.on("change:is_attach", function() {
+        setTimeout(function() {
+          self.columns.each(function(col) {
+            if (col.get('name') == 'partition_name') {
+              var idx = self.columns.indexOf(col),
+                cf = col.get("cellFunction"),
+                cell = new (cf.apply(col, [self.model]))({
+                  column: col,
+                  model: self.model
+                }),
+                  oldCell = self.cells[idx];
+                oldCell.remove();
+                self.cells[idx] = cell;
+                self.render();
+            }
+          });
+        }, 10);
+      });
+      self.listenTo(self.model, 'pgadmin-session:model:duplicate', self.modelDuplicate);
+      self.listenTo(self.model, 'pgadmin-session:model:unique', self.modelUnique);
+    },
+    modelDuplicate: function() {
+      $(this.el).removeClass("new");
+      this.el.style.backgroundColor = this.modelDuplicateColor;
+    },
+    modelUnique: function() {
+      this.el.style.backgroundColor = this.modelUniqueColor;
+    }
+  });
+
+  var getPartitionCell = function(model) {
+    var is_attach = model.get("is_attach");
+    if (is_attach) {
+      var options = [];
+      model.set({'partition_name': undefined}, {silent:true});
+      _.each(model.top.table_options, function(t) {
+        options.push([t.label, t.value]);
+      });
+      return Backgrid.Extension.Select2Cell.extend({optionValues: options});
+
+    } else {
+      return Backgrid.StringCell;
+    }
+  };
+
+  Backform.PartitionKeyModel = pgBrowser.Node.Model.extend({
+     defaults: {
+       key_type: 'column',
+       pt_column: undefined,
+       expression: undefined
+     },
+     keys:['pt_column'],
+     schema: [{
+       id: 'key_type', label:'Key type', type:'select2', editable: true,
+       cell:'select2', cellHeaderClasses: 'width_percent_25',
+       select2: {allowClear: false},
+       options:[{
+         label: 'Column', value: 'column'
+       },{
+         label: 'Expression', value: 'expression'
+       }]
+     },{
+       id: 'pt_column', label: gettext('Column'), type:'text',
+       cell: Backgrid.Extension.Select2DepCell.extend({
+         keyPathAccessor: function(obj, path) {
+           var res = obj;
+           if(_.isArray(res)) {
+             return _.map(res, function(o) { return o['pt_column']
+             });
+           }
+           path = path.split('.');
+           for (var i = 0; i < path.length; i++) {
+             if (_.isNull(res)) return null;
+             if (_.isEmpty(path[i])) continue;
+             if (!_.isUndefined(res[path[i]])) res = res[path[i]];
+           }
+           return _.isObject(res) && !_.isArray(res) ? null : res;
+         },
+         initialize: function() {
+         // Here we will decide if we need to call URL
+         // Or fetch the data from parent columns collection
+           var self = this;
+           if(this.model.handler) {
+             Backgrid.Extension.Select2DepCell.prototype.initialize.apply(this, arguments);
+             // Do not listen for any event(s) for existing constraint.
+             if (_.isUndefined(self.model.get('oid'))) {
+               var tableCols = self.model.top.get('columns');
+               self.listenTo(tableCols, 'remove' , self.resetColOptions);
+               self.listenTo(tableCols, 'change:name', self.resetColOptions);
+             }
+
+             self.custom_options();
+           }
+         },
+         resetColOptions: function(m) {
+           var self = this;
+
+           setTimeout(function () {
+             self.custom_options();
+             self.render.apply(self);
+           }, 50);
+         },
+         custom_options: function() {
+           // We will add all the columns entered by user in table model
+           var columns = this.model.top.get('columns'),
+             added_columns_from_tables = [];
+
+           if (columns.length > 0) {
+             _.each(columns.models, function(m) {
+                 var col = m.get('name');
+                 if(!_.isUndefined(col) && !_.isNull(col)) {
+                   added_columns_from_tables.push(
+                     {label: col, value: col, image:'icon-column'}
+                   );
+                 }
+             });
+           }
+           // Set the values in to options so that user can select
+           this.column.set('options', added_columns_from_tables);
+         },
+         remove: function() {
+           if(this.model.handler) {
+             var self = this,
+             tableCols = self.model.top.get('columns');
+             self.stopListening(tableCols, 'remove' , self.resetColOptions);
+             self.stopListening(tableCols, 'change:name' , self.resetColOptions);
+             Backgrid.Extension.Select2DepCell.prototype.remove.apply(this, arguments);
+           }
+         }
+       }),
+       deps: ['key_type'],
+       cellHeaderClasses: 'width_percent_30',
+       transform : function(data){
+         var res = [];
+         if (data && _.isArray(data)) {
+           _.each(data, function(d) {
+             res.push({label: d.label, value: d.label, image:'icon-column'});
+           })
+         }
+         return res;
+       },
+       select2:{allowClear:false},
+       editable: function(m) {
+         if (m.get('key_type') == 'expression') {
+           setTimeout( function() {
+              m.set('pt_column', undefined);
+           }, 10);
+           return false;
+         }
+         return true;
+       }
+     },{
+       id: 'expression', label:'Expression', type:'text',
+       cell:Backgrid.Extension.StringDepCell,
+       cellHeaderClasses: 'width_percent_45',
+       deps: ['key_type'],
+       editable: function(m) {
+         if (m.get('key_type') == 'column') {
+           setTimeout( function() {
+              m.set('expression', undefined);
+           }, 10);
+           return false;
+         }
+         return true;
+       }
+     }
+    ],
+    validate: function(keys) {
+      var col_type = this.get('key_type'),
+         pt_column = this.get('pt_column'),
+         expression = this.get('expression');
+
+      // Have to clear existing validation before initiating current state
+      // validation only
+      this.errorModel.clear();
+
+      if (_.isUndefined(col_type) || _.isNull(col_type) ||
+        String(col_type).replace(/^\s+|\s+$/g, '') == '') {
+        msg = gettext('Partition key type cannot be empty.');
+        this.errorModel.set('key_type', msg);
+        return msg;
+      }
+      else if (col_type == 'column' &&
+        _.isUndefined(pt_column) || _.isNull(pt_column) ||
+        String(pt_column).replace(/^\s+|\s+$/g, '') == '') {
+        msg = gettext('Partition key column cannot be empty.');
+        this.errorModel.set('pt_column', msg);
+        return msg;
+      }
+      else if (col_type == 'expression' &&
+        _.isUndefined(expression) || _.isNull(expression) ||
+        String(expression).replace(/^\s+|\s+$/g, '') == '') {
+        msg = gettext('Partition key expression cannot be empty.');
+        this.errorModel.set('expression', msg);
+        return msg;
+      }
+
+      return null;
+    }
+  });
+
+  Backform.PartitionsModel = pgBrowser.Node.Model.extend({
+    defaults: {
+      oid: undefined,
+      is_attach: false,
+      partition_name: undefined,
+      values_from: undefined,
+      values_to: undefined,
+      values_in: undefined
+    },
+    keys:['partition_name'],
+    schema: [{
+      id: 'oid', label: gettext('OID'), type: 'text'
+    },{
+      id: 'is_attach', label:gettext('Mode'), cell: 'switch',
+      type: 'switch', options: { 'onText': 'Attach', 'offText': 'Create'},
+      cellHeaderClasses: 'width_percent_5',
+      editable: function(m) {
+        if (m instanceof Backbone.Model && m.isNew() && !m.top.isNew())
+          return true;
+        return false;
+      }
+    },{
+      id: 'partition_name', label: gettext('Name'), type: 'text', cell:'string',
+      cellHeaderClasses: 'width_percent_25',
+      editable: function(m) {
+        if (m instanceof Backbone.Model && m.isNew())
+          return true;
+        return false;
+      }, cellFunction: getPartitionCell
+    },{
+      id: 'values_from', label:'From', type:'text',
+      cell:Backgrid.Extension.StringDepCell,
+      cellHeaderClasses: 'width_percent_20',
+      editable: function(m) {
+       if(m.handler && m.handler.top &&
+          m.handler.top.attributes &&
+          m.handler.top.attributes.partition_type == 'range' &&
+          m instanceof Backbone.Model && m.isNew())
+          return true;
+       return false;
+      }
+    },{
+      id: 'values_to', label:'To', type:'text',
+      cell:Backgrid.Extension.StringDepCell,
+      cellHeaderClasses: 'width_percent_20',
+      editable: function(m) {
+        if(m.handler && m.handler.top &&
+          m.handler.top.attributes &&
+          m.handler.top.attributes.partition_type == 'range' &&
+          m instanceof Backbone.Model && m.isNew())
+          return true;
+        return false;
+      }
+    },{
+      id: 'values_in', label:'In', type:'text',
+      cell:Backgrid.Extension.StringDepCell,
+      cellHeaderClasses: 'width_percent_25',
+      editable: function(m) {
+        if(m.handler && m.handler.top &&
+          m.handler.top.attributes &&
+          m.handler.top.attributes.partition_type == 'list' &&
+          m instanceof Backbone.Model && m.isNew())
+          return true;
+        return false;
+      }
+    }],
+    validate: function(keys) {
+      var partition_name = this.get('partition_name'),
+         values_from = this.get('values_from'),
+         values_to = this.get('values_to'),
+         values_in = this.get('values_in');
+
+      // Have to clear existing validation before initiating current state
+      // validation only
+      this.errorModel.clear();
+
+      if (_.isUndefined(partition_name) || _.isNull(partition_name) ||
+       String(partition_name).replace(/^\s+|\s+$/g, '') == '') {
+       msg = gettext('Partition name cannot be empty.');
+       this.errorModel.set('partition_name', msg);
+       return msg;
+      }
+
+      if (this.top.get('partition_type') == 'range') {
+        if (_.isUndefined(values_from) || _.isNull(values_from) ||
+          String(values_from).replace(/^\s+|\s+$/g, '') == '') {
+          msg = gettext('For range partition From field cannot be empty.');
+          this.errorModel.set('values_from', msg);
+          return msg;
+        } else if (_.isUndefined(values_to) || _.isNull(values_to) ||
+          String(values_to).replace(/^\s+|\s+$/g, '') == '') {
+          msg = gettext('For range partition To field cannot be empty.');
+          this.errorModel.set('values_to', msg);
+          return msg;
+        }
+      } else if (this.top.get('partition_type') == 'list') {
+        if (_.isUndefined(values_in) || _.isNull(values_in) ||
+          String(values_in).replace(/^\s+|\s+$/g, '') == '') {
+          msg = gettext('For list partition In field cannot be empty.');
+          this.errorModel.set('values_in', msg);
+          return msg;
+        }
+      }
+
+      return null;
+    }
+  });
+
+});
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js
index dbd171e..7b0c6b7 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/static/js/table.js
@@ -3,8 +3,10 @@ define('pgadmin.node.table', [
   'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify',
   'sources/alerts/alertify_wrapper',
   'pgadmin.browser.collection', 'pgadmin.node.column',
-  'pgadmin.node.constraints'
-], function(gettext, url_for, $, _, S, pgAdmin, pgBrowser, alertify, AlertifyWrapper) {
+  'pgadmin.node.constraints', 'pgadmin.browser.table.partition.utils'
+], function(
+  gettext, url_for, $, _, S, pgAdmin, pgBrowser, alertify, AlertifyWrapper
+) {
 
   if (!pgBrowser.Nodes['coll-table']) {
     var databases = pgBrowser.Nodes['coll-table'] =
@@ -12,7 +14,7 @@ define('pgadmin.node.table', [
         node: 'table',
         label: gettext('Tables'),
         type: 'coll-table',
-        columns: ['name', 'relowner', 'description'],
+        columns: ['name', 'relowner', 'is_partitioned', 'description'],
         hasStatistics: true,
         statsPrettifyFields: ['Size', 'Indexes size', 'Table size',
                               'Toast table size', 'Tuple length',
@@ -22,6 +24,7 @@ define('pgadmin.node.table', [
 
   if (!pgBrowser.Nodes['table']) {
     pgBrowser.Nodes['table'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
       type: 'table',
       label: gettext('Table'),
       collection_type: 'coll-table',
@@ -39,7 +42,7 @@ define('pgadmin.node.table', [
       height: '95%',
       width: '85%',
       Init: function() {
-        /* Avoid mulitple registration of menus */
+        /* Avoid multiple registration of menus */
         if (this.initialized)
             return;
 
@@ -284,7 +287,10 @@ define('pgadmin.node.table', [
           hastoasttable: true,
           toast_autovacuum_enabled: false,
           autovacuum_enabled: false,
-          primary_key: []
+          primary_key: [],
+          partitions: [],
+          partition_type: 'range',
+          is_partitioned: false
         },
         // Default values!
         initialize: function(attrs, args) {
@@ -330,12 +336,37 @@ define('pgadmin.node.table', [
             return (!(d && d.label.match(/pg_global/)))
           }
         },{
+          id: 'partition', type: 'group', label: gettext('Partition'),
+          mode: ['edit', 'create'], min_version: 100000,
+          visible: function(m) {
+            // Always show in case of create mode
+            if (m.isNew() || m.get('is_partitioned'))
+              return true;
+            return false;
+          }
+        },{
+          id: 'is_partitioned', label:gettext('Partitioned Table?'), cell: 'switch',
+          type: 'switch', mode: ['properties', 'create', 'edit'],
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (!m.isNew())
+              return true;
+            return false;
+          }
+        },{
           id: 'description', label: gettext('Comment'), type: 'multiline',
           mode: ['properties', 'create', 'edit'], disabled: 'inSchema'
         },{
           id: 'coll_inherits', label: gettext('Inherited from table(s)'),
           url: 'get_inherits', type: 'array', group: gettext('Columns'),
-          disabled: 'checkInheritance', deps: ['typname'],
+          disabled: 'checkInheritance', deps: ['typname', 'is_partitioned'],
           mode: ['create', 'edit'],
           select2: { multiple: true, allowClear: true,
           placeholder: gettext('Select to inherit from...')},
@@ -432,7 +463,26 @@ define('pgadmin.node.table', [
           model: pgBrowser.Nodes['column'].model,
           subnode: pgBrowser.Nodes['column'].model,
           mode: ['create', 'edit'],
-          disabled: 'inSchema', deps: ['typname'],
+          disabled: function(m) {
+            // In case of partitioned table remove inherited columns
+            if (m.isNew() && m.get('is_partitioned')) {
+              setTimeout(function() {
+                var coll = m.get('columns');
+                coll.remove(coll.filter(function(model) {
+                  if (_.isUndefined(model.get('inheritedfrom')))
+                    return false;
+                  return true;
+                }));
+              }, 10);
+            }
+
+            if(this.node_info &&  'catalog' in this.node_info)
+            {
+              return true;
+            }
+            return false;
+          },
+          deps: ['typname', 'is_partitioned'],
           canAdd: 'check_grid_add_condition',
           canEdit: true, canDelete: true,
           // For each row edit/delete button enable/disable
@@ -535,10 +585,22 @@ define('pgadmin.node.table', [
               subnode: pgBrowser.Nodes['primary_key'].model,
               editable: false, type: 'collection',
               group: gettext('Primary Key'), mode: ['edit', 'create'],
-              canEdit: true, canDelete: true,
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
               control: 'unique-col-collection',
               columns : ['name', 'columns'],
-              canAdd: true,
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('primary_key');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
               canAddRow: function(m) {
                // User can only add one primary key
                var columns = m.get('columns');
@@ -553,9 +615,21 @@ define('pgadmin.node.table', [
               subnode: pgBrowser.Nodes['foreign_key'].model,
               editable: false, type: 'collection',
               group: gettext('Foreign Key'), mode: ['edit', 'create'],
-              canEdit: true, canDelete: true,
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
               control: 'unique-col-collection',
-              canAdd: true,
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('foreign_key');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
               columns : ['name', 'columns'],
               canAddRow: function(m) {
                // User can only add if there is at least one column with name.
@@ -568,7 +642,7 @@ define('pgadmin.node.table', [
               subnode: pgBrowser.Nodes['check_constraints'].model,
               editable: false, type: 'collection',
               group: gettext('Check'), mode: ['edit', 'create'],
-              canEdit: true, canDelete: true,
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
               control: 'unique-col-collection',
               canAdd: true,
               columns : ['name', 'consrc']
@@ -578,10 +652,22 @@ define('pgadmin.node.table', [
               subnode: pgBrowser.Nodes['unique_constraint'].model,
               editable: false, type: 'collection',
               group: gettext('Unique'), mode: ['edit', 'create'],
-              canEdit: true, canDelete: true,
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
               control: 'unique-col-collection',
               columns : ['name', 'columns'],
-              canAdd: true,
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('unique_constraint');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
               canAddRow: function(m) {
                // User can only add if there is at least one column with name.
                var columns = m.get('columns');
@@ -593,10 +679,22 @@ define('pgadmin.node.table', [
               subnode: pgBrowser.Nodes['exclusion_constraint'].model,
               editable: false, type: 'collection',
               group: gettext('Exclude'), mode: ['edit', 'create'],
-              canEdit: true, canDelete: true,
+              canEdit: true, canDelete: true, deps:['is_partitioned'],
               control: 'unique-col-collection',
               columns : ['name', 'columns', 'constraint'],
-              canAdd: true,
+              canAdd: function(m) {
+                if (m.get('is_partitioned')) {
+                  setTimeout(function() {
+                    var coll = m.get('exclude_constraint');
+                    coll.remove(coll.filter(function(model) {
+                      return true;
+                    }));
+                  }, 10);
+                  return false;
+                }
+
+                return true;
+              },
               canAddRow: function(m) {
                // User can only add if there is at least one column with name.
                var columns = m.get('columns');
@@ -607,7 +705,7 @@ define('pgadmin.node.table', [
           id: 'typname', label: gettext('Of type'), type: 'text',
           control: 'node-ajax-options', mode: ['properties', 'create', 'edit'],
           disabled: 'checkOfType', url: 'get_oftype', group: gettext('Advanced'),
-          deps: ['coll_inherits'], transform: function(data, cell) {
+          deps: ['coll_inherits', 'is_partitioned'], transform: function(data, cell) {
             var control = cell || this,
               m = control.model;
               m.of_types_tables = data;
@@ -711,10 +809,180 @@ define('pgadmin.node.table', [
             disabled: 'isLikeDisable', group: gettext('Like')
           }]
         },{
+          id: 'partition_type', label:gettext('Partition Type'),
+          editable: false, type: 'select2', select2: {allowClear: false},
+          group: 'partition', deps: ['is_partitioned'],
+          options:[{
+            label: 'Range', value: 'range'
+          },{
+            label: 'List', value: 'list'
+          }],
+          mode:['create'],
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (!m.isNew() || !m.get('is_partitioned'))
+              return true;
+            return false;
+          }
+        },{
+          id: 'partition_keys', label:gettext('Partition Keys'),
+          model: Backform.PartitionKeyModel,
+          subnode: Backform.PartitionKeyModel,
+          editable: true, type: 'collection',
+          group: 'partition', mode: ['create'],
+          deps: ['is_partitioned', 'partition_type'],
+          canEdit: false, canDelete: true,
+          control: 'sub-node-collection',
+          canAdd: function(m) {
+            if (m.isNew() && m.get('is_partitioned'))
+              return true;
+            return false;
+          },
+          canAddRow: function(m) {
+            var columns = m.get('columns');
+            var max_row_count = 1000;
+
+            if (m.get('partition_type') && m.get('partition_type') == 'list')
+              max_row_count = 1;
+
+            return (m.get('partition_keys') &&
+                m.get('partition_keys').length < max_row_count &&
+                _.some(columns.pluck('name'))
+            );
+          },
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (m.get('partition_keys') && m.get('partition_keys').models.length > 0) {
+              setTimeout(function () {
+                var coll = m.get('partition_keys');
+                coll.remove(coll.filter(function(model) {
+                  return true;
+                }));
+              }, 10);
+            }
+          }
+        },{
+          id: 'partition_scheme', label: gettext('Partition Scheme'),
+          type: 'note', group: 'partition', mode: ['edit'],
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (!m.isNew()) {
+              this.text = m.get('partition_scheme');
+            }
+          }
+        },{
+          id: 'partitions', label:gettext('Partitions'),
+          model: Backform.PartitionsModel,
+          subnode: Backform.PartitionsModel,
+          editable: true, type: 'collection',
+          group: 'partition', mode: ['edit', 'create'],
+          deps: ['is_partitioned', 'partition_type'],
+          canEdit: false, canDelete: true,
+          customDeleteTitle: gettext('Detach Partition'),
+          customDeleteMsg: gettext('Are you sure you wish to detach this partition?'),
+          columns:['is_attach', 'partition_name', 'values_from', 'values_to', 'values_in'],
+          control: Backform.SubNodeCollectionControl.extend({
+            row: Backgrid.PartitionRow,
+            initialize: function() {
+              Backform.SubNodeCollectionControl.prototype.initialize.apply(this, arguments);
+              var self = this;
+              if (!this.model.isNew()) {
+                var node = this.field.get('schema_node'),
+                    node_info = this.field.get('node_info');
+
+                // Make ajax call to get the tables to be attached
+                $.ajax({
+                  url: node.generate_url.apply(
+                      node, [
+                        null, 'get_attach_tables', this.field.get('node_data'),
+                        true, node_info
+                      ]),
+
+                  type: 'GET',
+                  async: false,
+                  success: function(res) {
+                    if (res.success == 1) {
+                      self.model.table_options = res.data;
+                    }
+                    else {
+                      alertify.alert(
+                        'Error fetching tables to be attached', res.data.result
+                      );
+                    }
+                  },
+                  error: function(e) {
+                    var errmsg = $.parseJSON(e.responseText);
+                    alertify.alert('Error fetching tables to be attached.', errmsg.errormsg);
+                  }
+                });
+              }
+            }
+          }
+          ),
+          canAdd: function(m) {
+            if (m.get('is_partitioned'))
+              return true;
+            return false;
+          },
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          },
+          disabled: function(m) {
+            if (m.isNew() && m.get('partitions') && m.get('partitions').models.length > 0) {
+              setTimeout(function () {
+                var coll = m.get('partitions');
+                coll.remove(coll.filter(function(model) {
+                  return true;
+                }));
+              }, 10);
+            }
+          }
+        },{
+          id: 'partition_note', label: gettext('Partition'),
+          type: 'note', group: 'partition',
+          text: gettext('Above control will be used to Create/Attach/Detach partitions.<br>' +
+            '<ul><li>Create Mode: User will be able to create N number of partitions. Mode switch control is disabled in this scenario.</li>' +
+            '<li>Edit Mode: User will be able to create/attach/detach N number of partitions.' +
+            'In attach mode there will be list of suitable tables to be attached.</li></ul>'),
+          visible: function(m) {
+            if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server)
+              && !_.isUndefined(m.node_info.server.version) &&
+              m.node_info.server.version >= 100000)
+              return true;
+
+            return false;
+          }
+        },{
           // Here - we will create tab control for storage parameters
           // (auto vacuum).
           type: 'nested', control: 'tab', group: gettext('Parameter'),
-          mode: ['edit', 'create'],
+          mode: ['edit', 'create'], deps: ['is_partitioned'],
           schema: Backform.VacuumSettingsSchema
         },{
           id: 'relacl_str', label: gettext('Privileges'), disabled: 'inSchema',
@@ -741,7 +1009,9 @@ define('pgadmin.node.table', [
               msg = undefined,
               name = this.get('name'),
               schema = this.get('schema'),
-              relowner = this.get('relowner');
+              relowner = this.get('relowner'),
+              is_partitioned = this.get('is_partitioned'),
+              partition_keys = this.get('partition_keys');
 
           // If nothing to validate or VacuumSetting keys then
           // return from here
@@ -769,6 +1039,12 @@ define('pgadmin.node.table', [
             msg = gettext('Table owner cannot be empty.');
             this.errorModel.set('relowner', msg);
             return msg;
+          } else if (is_partitioned && this.isNew() &&
+            !_.isNull(partition_keys) && partition_keys.length <= 0)
+          {
+            msg = gettext('Please specify at least one key for partitioned table.');
+            this.errorModel.set('partition_keys', msg);
+            return msg;
           }
           return null;
         },
@@ -797,7 +1073,15 @@ define('pgadmin.node.table', [
         },
         // Oftype is defined?
         checkInheritance: function(m) {
-         // coll_inherits || typname
+          // Disabled if it is partitioned table
+          if (m.get('is_partitioned')) {
+            setTimeout( function() {
+               m.set('coll_inherits', []);
+            }, 10);
+            return true;
+          }
+
+          // coll_inherits || typname
           if(!m.inSchema.apply(this, [m]) &&
               ( _.isUndefined(m.get('typname')) ||
                 _.isNull(m.get('typname')) ||
@@ -841,7 +1125,15 @@ define('pgadmin.node.table', [
         },
         // We will disable it if Inheritance is defined
         checkOfType: function(m) {
-        //coll_inherits || typname
+          // Disabled if it is partitioned table
+          if (m.get('is_partitioned')) {
+            setTimeout( function() {
+               m.set('typname', undefined);
+            }, 10);
+            return true;
+          }
+
+          //coll_inherits || typname
           if(!m.inSchemaWithModelCheck.apply(this, [m]) &&
               (_.isUndefined(m.get('coll_inherits')) ||
                _.isNull(m.get('coll_inherits')) ||
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/attach.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/attach.sql
new file mode 100644
index 0000000..0661d9c
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/attach.sql
@@ -0,0 +1,2 @@
+ALTER TABLE {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}} ATTACH PARTITION {{conn|qtIdent(data.schema, data.name)}}
+    {{ data.partition_value }};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/backend_support.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/backend_support.sql
new file mode 100644
index 0000000..5fa1d7e
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/backend_support.sql
@@ -0,0 +1,9 @@
+{#=============Checks if it is partitioned table========#}
+{% if tid %}
+SELECT
+    CASE WHEN c.relkind = 'p' THEN True ELSE False END As ptable
+FROM
+    pg_class c
+WHERE
+    c.oid = {{ tid }}::oid
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/create.sql
new file mode 100644
index 0000000..b5e9404
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/create.sql
@@ -0,0 +1,30 @@
+{% import 'table/sql/macros/constraints.macro' as CONSTRAINTS %}
+{#===========================================#}
+{#====== MAIN TABLE TEMPLATE STARTS HERE ======#}
+{#===========================================#}
+{### CREATE TABLE STATEMENT FOR partitions ###}
+CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data.schema, data.name)}}{% if data.relispartition is defined and data.relispartition %} PARTITION OF {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}}{% endif %}
+
+{# Macro to render for constraints #}
+{% if 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.primary_key|length > 0 %}{{CONSTRAINTS.PRIMARY_KEY(conn, data.primary_key[0])}}{% endif %}{% if data.unique_constraint|length > 0 %}{% if data.primary_key|length > 0 %},{% endif %}
+{{CONSTRAINTS.UNIQUE(conn, data.unique_constraint)}}{% endif %}{% if data.foreign_key|length > 0 %}{% if 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.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.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.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 %}
+    {{ data.partition_value }}{% if data.is_partitioned is defined and data.is_partitioned %}
+
+    PARTITION BY {{ data.partition_scheme }}{% endif %};
+
+
+{### Alter SQL for Owner ###}
+{% if data.relowner %}
+
+ALTER TABLE {{conn|qtIdent(data.schema, data.name)}}
+    OWNER to {{conn|qtIdent(data.relowner)}};
+{% endif %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/detach.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/detach.sql
new file mode 100644
index 0000000..4b413db
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/detach.sql
@@ -0,0 +1 @@
+ALTER TABLE {{conn|qtIdent(data.parent_schema, data.partitioned_table_name)}} DETACH PARTITION {{conn|qtIdent(data.schema, data.name)}};
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/get_attach_tables.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/get_attach_tables.sql
new file mode 100644
index 0000000..476dc3f
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/get_attach_tables.sql
@@ -0,0 +1,23 @@
+SELECT oid, quote_ident(nspname)||'.'||quote_ident(relname) AS table_name FROM
+(SELECT
+	r.oid, r.relname, n.nspname, array_agg(a.attname) attnames, array_agg(a.atttypid) atttypes
+FROM
+	(SELECT oid, relname, relnamespace FROM pg_catalog.pg_class
+	  WHERE relkind in ('r', 'p') AND NOT relispartition) r
+    JOIN (SELECT oid AS nspoid, nspname FROM
+          pg_catalog.pg_namespace WHERE nspname NOT LIKE E'pg\_%') n
+          ON (r.relnamespace = n.nspoid)
+    JOIN (SELECT attrelid, attname, atttypid FROM
+          pg_catalog.pg_attribute WHERE attnum > 0 ORDER BY attrelid, attnum) a
+          ON (r.oid = a.attrelid)
+GROUP BY r.oid, r.relname, r.relnamespace, n.nspname) all_tables
+JOIN
+(SELECT
+	attrelid, array_agg(attname) attnames, array_agg(atttypid) atttypes
+FROM
+	(SELECT * FROM pg_catalog.pg_attribute
+	  WHERE attrelid = {{ tid }} AND attnum > 0
+	  ORDER BY attrelid, attnum) attributes
+GROUP BY attrelid) current_table ON current_table.attrelid != all_tables.oid
+  AND current_table.attnames = all_tables.attnames
+  AND current_table.atttypes = all_tables.atttypes
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/nodes.sql
new file mode 100644
index 0000000..bd828cd
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/nodes.sql
@@ -0,0 +1,15 @@
+SELECT rel.oid, rel.relname AS name,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers,
+    pg_get_expr(rel.relpartbound, rel.oid) AS partition_value,
+    rel.relnamespace AS schema_id,
+    nsp.nspname AS schema_name,
+    (CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
+    (CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme
+FROM
+    (SELECT * FROM pg_inherits WHERE inhparent = {{ tid }}::oid) inh
+    LEFT JOIN pg_class rel ON inh.inhrelid = rel.oid
+    LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
+    WHERE rel.relispartition
+    {% if ptid %} AND rel.oid = {{ ptid }}::OID {% endif %}
+    ORDER BY rel.relname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/properties.sql
new file mode 100644
index 0000000..85f4476
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/partition/sql/10_plus/properties.sql
@@ -0,0 +1,82 @@
+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 parent_schema,
+  nsp.nspname as schema,
+  pg_get_userbyid(rel.relowner) AS relowner, rel.relhasoids, rel.relispartition,
+  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 AND tgisinternal = FALSE) 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 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,
+	(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
+	substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
+	(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, rel.reloftype, typ.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,
+
+	(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
+	(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table,
+	-- Added for partition table
+	(CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
+	(CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef(rel.oid::oid) ELSE '' END) AS partition_scheme,
+	{% if ptid %}
+	  (CASE WHEN rel.relispartition THEN pg_get_expr(rel.relpartbound, {{ ptid }}::oid) ELSE '' END) AS partition_value,
+	  (SELECT relname FROM pg_class WHERE oid = {{ tid }}::oid) AS partitioned_table_name
+	{% else %}
+	  pg_get_expr(rel.relpartbound, rel.oid) AS partition_value
+	{% endif %}
+
+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 JOIN pg_type typ ON rel.reloftype=typ.oid
+  LEFT JOIN pg_inherits inh ON inh.inhrelid = rel.oid
+  LEFT JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
+WHERE rel.relispartition AND inh.inhparent = {{ tid }}::oid
+{% if ptid %}  AND rel.oid = {{ ptid }}::oid {% endif %}
+ORDER BY rel.relname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/acl.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/acl.sql
new file mode 100644
index 0000000..eadf9d5
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/acl.sql
@@ -0,0 +1,46 @@
+{### SQL to fetch privileges for tablespace ###}
+SELECT 'relacl' as deftype, COALESCE(gt.rolname, 'PUBLIC') grantee, g.rolname grantor,
+    array_agg(privilege_type) as privileges, array_agg(is_grantable) as grantable
+FROM
+  (SELECT
+    d.grantee, d.grantor, d.is_grantable,
+    CASE d.privilege_type
+		WHEN 'CONNECT' THEN 'c'
+		WHEN 'CREATE' THEN 'C'
+		WHEN 'DELETE' THEN 'd'
+		WHEN 'EXECUTE' THEN 'X'
+		WHEN 'INSERT' THEN 'a'
+		WHEN 'REFERENCES' THEN 'x'
+		WHEN 'SELECT' THEN 'r'
+		WHEN 'TEMPORARY' THEN 'T'
+		WHEN 'TRIGGER' THEN 't'
+		WHEN 'TRUNCATE' THEN 'D'
+		WHEN 'UPDATE' THEN 'w'
+		WHEN 'USAGE' THEN 'U'
+		ELSE 'UNKNOWN'
+	END AS privilege_type
+  FROM
+    (SELECT rel.relacl
+        FROM pg_class rel
+          LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+          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 JOIN pg_type typ ON rel.reloftype=typ.oid
+        WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
+            AND rel.oid = {{ tid }}::oid
+    ) acl,
+    (SELECT (d).grantee AS grantee, (d).grantor AS grantor, (d).is_grantable
+        AS is_grantable, (d).privilege_type AS privilege_type FROM (SELECT
+        aclexplode(rel.relacl) as d
+        FROM pg_class rel
+          LEFT OUTER JOIN pg_tablespace spc on spc.oid=rel.reltablespace
+          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 JOIN pg_type typ ON rel.reloftype=typ.oid
+        WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
+            AND rel.oid = {{ tid }}::oid
+        ) a) d
+    ) d
+  LEFT JOIN pg_catalog.pg_roles g ON (d.grantor = g.oid)
+  LEFT JOIN pg_catalog.pg_roles gt ON (d.grantee = gt.oid)
+GROUP BY g.rolname, gt.rolname
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_inherits.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_inherits.sql
new file mode 100644
index 0000000..f28f298
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_inherits.sql
@@ -0,0 +1,17 @@
+{% import 'table/sql/macros/db_catalogs.macro' as CATALOG %}
+SELECT c.oid, c.relname , nspname,
+CASE WHEN nspname NOT LIKE E'pg\_%' THEN
+ quote_ident(nspname)||'.'||quote_ident(c.relname)
+ELSE quote_ident(c.relname)
+END AS inherits
+FROM pg_class c
+JOIN pg_namespace n
+ON n.oid=c.relnamespace
+WHERE relkind='r' AND NOT relispartition
+{% if not show_system_objects %}
+{{ CATALOG.VALID_CATALOGS(server_type) }}
+{% endif %}
+{% if tid %}
+AND c.oid != tid
+{% endif %}
+ORDER BY relnamespace, c.relname
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_oid.sql
new file mode 100644
index 0000000..f630698
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_oid.sql
@@ -0,0 +1,5 @@
+SELECT rel.oid as tid
+FROM pg_class rel
+WHERE rel.relkind IN ('r','s','t','p')
+AND rel.relnamespace = {{ scid }}::oid
+AND rel.relname = {{data.name|qtLiteral}}
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_table.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_table.sql
new file mode 100644
index 0000000..6952c8d
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/get_table.sql
@@ -0,0 +1,8 @@
+SELECT
+    rel.relname AS name
+FROM
+    pg_class rel
+WHERE
+    rel.relkind IN ('r','s','t','p')
+    AND rel.relnamespace = {{ scid }}::oid
+    AND rel.oid = {{ tid }}::oid;
\ No newline at end of file
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/nodes.sql
new file mode 100644
index 0000000..fbf9c42
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/nodes.sql
@@ -0,0 +1,9 @@
+SELECT rel.oid, rel.relname AS name,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE) AS triggercount,
+    (SELECT count(*) FROM pg_trigger WHERE tgrelid=rel.oid AND tgisinternal = FALSE AND tgenabled = 'O') AS has_enable_triggers,
+    (CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned
+FROM pg_class rel
+    WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
+    AND NOT rel.relispartition
+    {% if tid %} AND rel.oid = {{tid}}::OID {% endif %}
+    ORDER BY rel.relname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql
new file mode 100644
index 0000000..1d589df
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/10_plus/properties.sql
@@ -0,0 +1,73 @@
+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.relkind,
+  (CASE WHEN rel.relkind = 'p' THEN true ELSE false END) AS is_partitioned,
+  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 AND tgisinternal = FALSE) 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 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,
+	(CASE WHEN rel.relpersistence = 'u' THEN true ELSE false END) AS relpersistence,
+	substring(array_to_string(rel.reloptions, ',') FROM 'fillfactor=([0-9]*)') AS fillfactor,
+	(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, rel.reloftype, typ.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,
+
+	(SELECT array_agg(provider || '=' || label) FROM pg_seclabels sl1 WHERE sl1.objoid=rel.oid AND sl1.objsubid=0) AS seclabels,
+	(CASE WHEN rel.oid <= {{ datlastsysoid}}::oid THEN true ElSE false END) AS is_sys_table
+	-- Added for partition table
+    {% if tid %}, (CASE WHEN rel.relkind = 'p' THEN pg_get_partkeydef({{ tid }}::oid) ELSE '' END) AS partition_scheme {% endif %}
+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 JOIN pg_type typ ON rel.reloftype=typ.oid
+WHERE rel.relkind IN ('r','s','t','p') AND rel.relnamespace = {{ scid }}::oid
+AND NOT rel.relispartition
+{% if tid %}  AND rel.oid = {{ tid }}::oid {% endif %}
+ORDER BY rel.relname;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/create.sql
index f8e858f..5ec8ffc 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/create.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/create.sql
@@ -57,7 +57,8 @@ CREATE {% if data.relpersistence %}UNLOGGED {% endif %}TABLE {{conn|qtIdent(data
 {{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 %}
 
-)
+){% if data.relkind is defined and data.relkind == 'p' %} PARTITION BY {{ data.partition_scheme }} {% endif %}
+
 {% endif %}
 {### If we are inheriting it from another table(s) ###}
 {% if data.coll_inherits %}
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/get_schema_oid.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/get_schema_oid.sql
index 4d329d2..8df84b5 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/get_schema_oid.sql
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/table/sql/default/get_schema_oid.sql
@@ -1,8 +1,9 @@
 {# ===== fetch new assigned schema oid ===== #}
 SELECT
-    c.relnamespace as scid
+    c.relnamespace as scid, nsp.nspname as nspname
 FROM
     pg_class c
+LEFT JOIN pg_namespace nsp ON nsp.oid = c.relnamespace
 WHERE
 {% if tid %}
     c.oid = {{tid}}::oid;
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_add.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_add.py
index 0703cba..9e4846c 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_add.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_add.py
@@ -14,6 +14,7 @@ from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
     utils as schema_utils
 from pgadmin.browser.server_groups.servers.databases.tests import utils as \
     database_utils
+from pgadmin.browser.server_groups.servers.tests import utils as server_utils
 from pgadmin.utils.route import BaseTestGenerator
 from regression import parent_node_dict
 from regression.python_test_utils import test_utils as utils
@@ -23,7 +24,19 @@ class TableAddTestCase(BaseTestGenerator):
     """ This class will add new collation under schema node. """
     scenarios = [
         # Fetching default URL for table node.
-        ('Fetch table Node URL', dict(url='/browser/table/obj/'))
+        ('Create Table', dict(url='/browser/table/obj/')),
+        ('Create Range partitioned table with 2 partitions',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='range'
+              )
+         ),
+        ('Create List partitioned table with 2 partitions',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='list'
+              )
+         )
     ]
 
     def setUp(self):
@@ -43,6 +56,19 @@ class TableAddTestCase(BaseTestGenerator):
         if not schema_response:
             raise Exception("Could not find the schema to add a table.")
 
+        self.is_partition = False
+        if hasattr(self, 'server_min_version'):
+            server_con = server_utils.connect_server(self, self.server_id)
+            if not server_con["info"] == "Server connected.":
+                raise Exception("Could not connect to server to add "
+                                "partitioned table.")
+            if server_con["data"]["version"] < self.server_min_version:
+                message = "Partitioned table are not supported by " \
+                          "PPAS/PG 10.0 and below."
+                self.skipTest(message)
+            else:
+                self.is_partition = True
+
     def runTest(self):
         """ This function will add table under schema node. """
         db_user = self.server["username"]
@@ -68,7 +94,7 @@ class TableAddTestCase(BaseTestGenerator):
                     "seclabels": []
                 },
                 {"name": "DOJ",
-                 "cltype": "date[]",
+                 "cltype": "date",
                  "attacl": [],
                  "is_primary_key": False,
                  "attoptions": [],
@@ -76,7 +102,7 @@ class TableAddTestCase(BaseTestGenerator):
                  }
             ],
             "exclude_constraint": [],
-            "fillfactor": "11",
+            "fillfactor": "",
             "hastoasttable": True,
             "like_constraints": True,
             "like_default_value": True,
@@ -166,6 +192,35 @@ class TableAddTestCase(BaseTestGenerator):
                 }
             ]
         }
+
+        if self.is_partition:
+            data['partition_type'] = self.partition_type
+            data['is_partitioned'] = True
+            if self.partition_type == 'range':
+                data['partitions'] = \
+                    [{'values_from': "'2010-01-01'",
+                      'values_to': "'2010-12-31'",
+                      'is_attach': False,
+                      'partition_name': 'emp_2010'
+                      },
+                     {'values_from': "'2011-01-01'",
+                      'values_to': "'2011-12-31'",
+                      'is_attach': False,
+                      'partition_name': 'emp_2011'
+                      }]
+            else:
+                data['partitions'] = \
+                    [{'values_in': "'2012-01-01', '2012-12-31'",
+                      'is_attach': False,
+                      'partition_name': 'emp_2012'
+                      },
+                     {'values_in': "'2013-01-01', '2013-12-31'",
+                      'is_attach': False,
+                      'partition_name': 'emp_2013'
+                      }]
+            data['partition_keys'] = \
+                [{'key_type': 'column', 'pt_column': 'DOJ'}]
+
         # Add table
         response = self.tester.post(
             self.url + str(utils.SERVER_GROUP) + '/' +
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_delete.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_delete.py
index 1b2f9f5..9749fed 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_delete.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_delete.py
@@ -23,7 +23,7 @@ class TableDeleteTestCase(BaseTestGenerator):
     """This class will delete new table under schema node."""
     scenarios = [
         # Fetching default URL for table node.
-        ('Fetch table Node URL', dict(url='/browser/table/obj/'))
+        ('Delete Table', dict(url='/browser/table/obj/'))
     ]
 
     def setUp(self):
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_put.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_put.py
index bfbf884..ef476d7 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_put.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/test_table_put.py
@@ -14,6 +14,7 @@ from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
     utils as schema_utils
 from pgadmin.browser.server_groups.servers.databases.tests import utils as \
     database_utils
+from pgadmin.browser.server_groups.servers.tests import utils as server_utils
 from pgadmin.utils.route import BaseTestGenerator
 from regression import parent_node_dict
 from regression.python_test_utils import test_utils as utils
@@ -24,7 +25,49 @@ class TableUpdateTestCase(BaseTestGenerator):
     """This class will add new collation under schema node."""
     scenarios = [
         # Fetching default URL for table node.
-        ('Fetch table Node URL', dict(url='/browser/table/obj/'))
+        ('Update Table', dict(url='/browser/table/obj/')),
+        ('Create partitions of existing range partitioned table',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='range',
+              mode='create'
+              )
+         ),
+        ('Create partitions of existing list partitioned table',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='list',
+              mode='create'
+              )
+         ),
+        ('Detach partition from existing range partitioned table',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='range',
+              mode='detach'
+              )
+         ),
+        ('Detach partition from existing list partitioned table',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='list',
+              mode='detach'
+              )
+         ),
+        ('Attach partition to existing range partitioned table',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='range',
+              mode='attach'
+              )
+         ),
+        ('Attach partition to existing list partitioned table',
+         dict(url='/browser/table/obj/',
+              server_min_version=100000,
+              partition_type='list',
+              mode='attach'
+              )
+         )
     ]
 
     def setUp(self):
@@ -44,9 +87,31 @@ class TableUpdateTestCase(BaseTestGenerator):
         if not schema_response:
             raise Exception("Could not find the schema to add a table.")
         self.table_name = "test_table_put_%s" % (str(uuid.uuid4())[1:6])
-        self.table_id = tables_utils.create_table(self.server, self.db_name,
-                                                  self.schema_name,
-                                                  self.table_name)
+
+        self.is_partition = False
+        if hasattr(self, 'server_min_version'):
+            server_con = server_utils.connect_server(self, self.server_id)
+            if not server_con["info"] == "Server connected.":
+                raise Exception("Could not connect to server to add "
+                                "partitioned table.")
+            if server_con["data"]["version"] < self.server_min_version:
+                message = "Partitioned table are not supported by " \
+                          "PPAS/PG 10.0 and below."
+                self.skipTest(message)
+            else:
+                self.is_partition = True
+
+            self.table_id = tables_utils.create_table_for_partition(
+                self.server,
+                self.db_name,
+                self.schema_name,
+                self.table_name,
+                'partitioned',
+                self.partition_type)
+        else:
+            self.table_id = tables_utils.create_table(self.server, self.db_name,
+                                                      self.schema_name,
+                                                      self.table_name)
 
     def runTest(self):
         """This function will fetch added table under schema node."""
@@ -54,10 +119,18 @@ class TableUpdateTestCase(BaseTestGenerator):
                                                    self.table_id)
         if not table_response:
             raise Exception("Could not find the table to update.")
-        data = {
-            "description": "This is test comment for table",
-            "id": self.table_id
-        }
+
+        if self.is_partition:
+            data = {"id": self.table_id}
+            tables_utils.set_partition_data(
+                self.server, self.db_name, self.schema_name, self.table_name,
+                self.partition_type, data, self.mode)
+        else:
+            data = {
+                "description": "This is test comment for table",
+                "id": self.table_id
+            }
+
         response = self.tester.put(
             self.url + str(utils.SERVER_GROUP) + '/' +
             str(self.server_id) + '/' + str(self.db_id) + '/' +
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/utils.py
index 456f020..0c7aede 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/tests/utils.py
@@ -85,3 +85,153 @@ def verify_table(server, db_name, table_id):
     except Exception:
         traceback.print_exc(file=sys.stderr)
         raise
+
+
+def create_table_for_partition(server, db_name, schema_name, table_name,
+                               table_type, partition_type, partition_name=None):
+    """
+    This function creates partitioned/partition/regular table
+    under provided schema.
+
+    :param server: server details
+    :param db_name: database name
+    :param schema_name: schema name
+    :param table_name: table name
+    :param table_type: regular/partitioned/partition
+    :param partition_type: partition table type (range/list)
+    :param partition_name: Partition Name
+    :return table_id: table id
+    """
+    try:
+        connection = utils.get_db_connection(db_name,
+                                             server['username'],
+                                             server['db_password'],
+                                             server['host'],
+                                             server['port'])
+        old_isolation_level = connection.isolation_level
+        connection.set_isolation_level(0)
+        pg_cursor = connection.cursor()
+
+        query = ''
+        if table_type == 'partitioned':
+            if partition_type == 'range':
+                query = "CREATE TABLE %s.%s(country text, sales bigint, " \
+                        "saledate date) PARTITION BY RANGE(saledate)" % \
+                        (schema_name, table_name)
+            else:
+                query = "CREATE TABLE %s.%s(country text, sales bigint, " \
+                        "saledate date) PARTITION BY LIST(saledate)" % \
+                        (schema_name, table_name)
+        elif table_type == 'partition':
+            if partition_type == 'range':
+                query = "CREATE TABLE %s.%s PARTITION OF %s.%s " \
+                        "FOR VALUES FROM ('2012-01-01') TO ('2012-12-31')" % \
+                        (schema_name, partition_name, schema_name, table_name)
+            else:
+                query = "CREATE TABLE %s.%s PARTITION OF %s.%s " \
+                        "FOR VALUES IN ('2013-01-01')" % \
+                        (schema_name, partition_name, schema_name, table_name)
+
+            # To fetch OID table name is actually partition name
+            table_name = partition_name
+        elif table_type == 'regular':
+            query = "CREATE TABLE %s.%s(country text, sales bigint," \
+                    "saledate date NOT NULL)" % (schema_name, table_name)
+
+        pg_cursor.execute(query)
+        connection.set_isolation_level(old_isolation_level)
+        connection.commit()
+        # Get 'oid' from newly created table
+        pg_cursor.execute("select oid from pg_class where relname='%s'" %
+                          table_name)
+        table = pg_cursor.fetchone()
+        table_id = ''
+        if table:
+            table_id = table[0]
+        connection.close()
+        return table_id
+    except Exception:
+        traceback.print_exc(file=sys.stderr)
+        raise
+
+
+def set_partition_data(server, db_name, schema_name, table_name,
+                       partition_type, data, mode):
+    """
+    This function is used to set the partitions data on the basis of
+    partition type and action.
+
+    :param server: server details
+    :param db_name: Database Name
+    :param schema_name: Schema Name
+    :param table_name: Table Name
+    :param partition_type: range or list
+    :param data: Data
+    :param mode: create/detach
+    :return:
+    """
+
+    data['partitions'] = dict()
+    if partition_type == 'range' and mode == 'create':
+        data['partitions'].update(
+            {'added': [{'values_from': "'2014-01-01'",
+                        'values_to': "'2014-12-31'",
+                        'is_attach': False,
+                        'partition_name': 'sale_2014'},
+                       {'values_from': "'2015-01-01'",
+                        'values_to': "'2015-12-31'",
+                        'is_attach': False,
+                        'partition_name': 'sale_2015'
+                        }]
+             }
+        )
+    elif partition_type == 'list' and mode == 'create':
+        data['partitions'].update(
+            {'added': [{'values_in': "'2016-01-01', '2016-12-31'",
+                        'is_attach': False,
+                        'partition_name': 'sale_2016'},
+                       {'values_in': "'2017-01-01', '2017-12-31'",
+                        'is_attach': False,
+                        'partition_name': 'sale_2017'
+                        }]
+             }
+        )
+    elif partition_type == 'range' and mode == 'detach':
+        partition_id = create_table_for_partition(server, db_name, schema_name,
+                                                  table_name, 'partition',
+                                                  partition_type, 'sale_2012')
+        data['partitions'].update(
+            {'deleted': [{'oid': partition_id}]
+             }
+        )
+    elif partition_type == 'list' and mode == 'detach':
+        partition_id = create_table_for_partition(server, db_name, schema_name,
+                                                  table_name, 'partition',
+                                                  partition_type, 'sale_2013')
+        data['partitions'].update(
+            {'deleted': [{'oid': partition_id}]
+             }
+        )
+    elif partition_type == 'range' and mode == 'attach':
+        partition_id = create_table_for_partition(server, db_name, schema_name,
+                                                  'attach_sale_2010', 'regular',
+                                                  partition_type)
+        data['partitions'].update(
+            {'added': [{'values_from': "'2010-01-01'",
+                        'values_to': "'2010-12-31'",
+                        'is_attach': True,
+                        'partition_name': partition_id
+                        }]
+             }
+        )
+    elif partition_type == 'list' and mode == 'attach':
+        partition_id = create_table_for_partition(server, db_name, schema_name,
+                                                  'attach_sale_2011', 'regular',
+                                                  partition_type)
+        data['partitions'].update(
+            {'added': [{'values_in': "'2011-01-01'",
+                        'is_attach': True,
+                        'partition_name': partition_id
+                        }]
+             }
+        )
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js
index 1623fe5..87f1eb3 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/templates/trigger/js/trigger.js
@@ -30,13 +30,15 @@ define('pgadmin.node.trigger', [
         node: 'trigger',
         label: gettext('Triggers'),
         type: 'coll-trigger',
+        getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
         columns: ['name', 'description']
       });
   };
 
   if (!pgBrowser.Nodes['trigger']) {
-    pgAdmin.Browser.Nodes['trigger'] = pgAdmin.Browser.Node.extend({
-      parent_type: ['table', 'view'],
+    pgAdmin.Browser.Nodes['trigger'] = pgBrowser.Node.extend({
+      getTreeNodeHierarchy: pgBrowser.tableChildTreeNodeHierarchy,
+      parent_type: ['table', 'view', 'partition'],
       collection_type: ['coll-table', 'coll-view'],
       type: 'trigger',
       label: gettext('Trigger'),
@@ -72,6 +74,12 @@ define('pgadmin.node.trigger', [
           icon: 'wcTabIcon icon-trigger', data: {action: 'create', check: true},
           enable: 'canCreate'
         },{
+          name: 'create_trigger_onPartition', node: 'partition', module: this,
+          applies: ['object', 'context'], callback: 'show_obj_properties',
+          category: 'create', priority: 4, label: gettext('Trigger...'),
+          icon: 'wcTabIcon icon-trigger', data: {action: 'create', check: true},
+          enable: 'canCreate'
+        },{
           name: 'enable_trigger', node: 'trigger', module: this,
           applies: ['object', 'context'], callback: 'enable_trigger',
           category: 'connect', priority: 3, label: gettext('Enable trigger'),
@@ -206,6 +214,17 @@ define('pgadmin.node.trigger', [
           mode: ['create','edit', 'properties'],
           deps: ['is_constraint_trigger'],
           disabled: function(m) {
+            // Disabled if table is a partitioned table.
+            if (_.has(m, 'node_info') && _.has(m.node_info, 'table') &&
+                _.has(m.node_info.table, 'is_partitioned') && m.node_info.table.is_partitioned)
+            {
+              setTimeout(function(){
+                  m.set('is_row_trigger', false);
+              },10);
+
+              return true;
+            }
+
             // If constraint trigger is set to True then row trigger will
             // automatically set to True and becomes disable
             var is_constraint_trigger = m.get('is_constraint_trigger');
@@ -232,7 +251,19 @@ define('pgadmin.node.trigger', [
           id: 'is_constraint_trigger', label: gettext('Constraint trigger?'),
           type: 'switch', disabled: 'inSchemaWithModelCheck',
           mode: ['create','edit', 'properties'],
-          group: gettext('Definition')
+          group: gettext('Definition'),
+          disabled: function(m) {
+            // Disabled if table is a partitioned table.
+            if (_.has(m, 'node_info') && _.has(m.node_info, 'table') &&
+                _.has(m.node_info.table, 'is_partitioned') && m.node_info.table.is_partitioned)
+            {
+              setTimeout(function(){
+                  m.set('is_constraint_trigger', false);
+              },10);
+
+              return true;
+            }
+          }
         },{
           id: 'tgdeferrable', label: gettext('Deferrable?'),
           type: 'switch', group: gettext('Definition'),
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
new file mode 100644
index 0000000..7709e1a
--- /dev/null
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/utils.py
@@ -0,0 +1,2112 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2017, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+""" Implements Utility class for Table and Partitioned Table. """
+
+import re
+from functools import wraps
+import simplejson as json
+from flask import render_template, jsonify, request
+from flask_babel import gettext
+from pgadmin.utils.ajax import make_json_response, internal_server_error, \
+    make_response as ajax_response, gone
+from pgadmin.browser.server_groups.servers.databases.schemas.utils \
+    import DataTypeReader, trigger_definition, parse_rule_definition
+from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \
+    parse_priv_to_db
+from pgadmin.browser.utils import PGChildNodeView
+from pgadmin.utils.driver import get_driver
+from config import PG_DEFAULT_DRIVER
+
+
+class BaseTableView(PGChildNodeView):
+    """
+    This class is base class for tables and partitioned tables.
+
+    Methods:
+    -------
+    * check_precondition()
+      - This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+
+    * _formatter(data, tid)
+      - It will return formatted output of query result
+        as per client model format
+
+    * _columns_formatter(tid, data):
+      - It will return formatted output of query result
+        as per client model format for column node
+
+    * _index_constraints_formatter(self, did, tid, data):
+      - It will return formatted output of query result
+        as per client model format for index constraint node
+
+    * _cltype_formatter(type): (staticmethod)
+      - We need to remove [] from type and append it
+        after length/precision so we will send flag for
+        sql template.
+
+    * get_table_dependents(self, tid):
+      - This function get the dependents and return ajax response
+        for the table node.
+
+    * get_table_dependencies(self, tid):
+      - This function get the dependencies and return ajax response
+        for the table node.
+
+    * get_table_statistics(self, tid):
+      - Returns the statistics for a particular table if tid is specified,
+        otherwise it will return statistics for all the tables in that
+        schema.
+    * get_reverse_engineered_sql(self, did, scid, tid, main_sql, data):
+      - This function will creates reverse engineered sql for
+        the table object.
+
+    * reset_statistics(self, scid, tid):
+      - This function will reset statistics of table.
+    """
+    @staticmethod
+    def check_precondition(f):
+        """
+        This function will behave as a decorator which will checks
+        database connection before running view, it will also attaches
+        manager,conn & template_path properties to self
+        """
+
+        @wraps(f)
+        def wrap(*args, **kwargs):
+            # Here args[0] will hold self & kwargs will hold gid,sid,did
+            self = args[0]
+            driver = get_driver(PG_DEFAULT_DRIVER)
+            did = kwargs['did']
+            self.manager = driver.connection_manager(kwargs['sid'])
+            self.conn = self.manager.connection(did=kwargs['did'])
+            self.qtIdent = driver.qtIdent
+            self.qtTypeIdent = driver.qtTypeIdent
+            # We need datlastsysoid to check if current table is system table
+            self.datlastsysoid = self.manager.db_info[
+                did
+            ]['datlastsysoid'] if self.manager.db_info is not None and \
+                did in self.manager.db_info else 0
+
+            ver = self.manager.version
+            # Set the template path for the SQL scripts
+            self.table_template_path = 'table/sql/#{0}#'.format(ver)
+            self.partition_template_path = 'partition/sql/#{0}#'.format(ver)
+
+            # Template for Column ,check constraint and exclusion
+            # constraint node
+            self.column_template_path = 'column/sql/#{0}#'.format(ver)
+            self.check_constraint_template_path = \
+                'check_constraint/sql/#{0}#'.format(ver)
+            self.exclusion_constraint_template_path = \
+                'exclusion_constraint/sql/#{0}#'.format(ver)
+
+            # Template for PK & Unique constraint node
+            self.index_constraint_template_path = 'index_constraint/sql'
+
+            # Template for foreign key constraint node
+            self.foreign_key_template_path = 'foreign_key/sql/#{0}#'.format(ver)
+
+            # Template for index node
+            self.index_template_path = 'index/sql/#{0}#'.format(ver)
+
+            # Template for trigger node
+            self.trigger_template_path = 'trigger/sql/#{0}#'.format(ver)
+
+            # Template for rules node
+            self.rules_template_path = 'rules/sql'
+
+            # Supported ACL for table
+            self.acl = ['a', 'r', 'w', 'd', 'D', 'x', 't']
+
+            # Supported ACL for columns
+            self.column_acl = ['a', 'r', 'w', 'x']
+
+            return f(*args, **kwargs)
+
+        return wrap
+
+    def _columns_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for column node
+        """
+        for column in data['columns']:
+
+            # We need to format variables according to client js collection
+            if 'attoptions' in column and column['attoptions'] is not None:
+                spcoptions = []
+                for spcoption in column['attoptions']:
+                    k, v = spcoption.split('=')
+                    spcoptions.append({'name': k, 'value': v})
+
+                column['attoptions'] = spcoptions
+
+            # Need to format security labels according to client js collection
+            if 'seclabels' in column and column['seclabels'] is not None:
+                seclabels = []
+                for seclbls in column['seclabels']:
+                    k, v = seclbls.split('=')
+                    seclabels.append({'provider': k, 'label': v})
+
+                column['seclabels'] = seclabels
+
+            if 'attnum' in column and column['attnum'] is not None \
+                    and column['attnum'] > 0:
+                # We need to parse & convert ACL coming from database to
+                # json format
+                SQL = render_template("/".join(
+                    [self.column_template_path, 'acl.sql']),
+                    tid=tid, clid=column['attnum']
+                )
+                status, acl = self.conn.execute_dict(SQL)
+
+                if not status:
+                    return internal_server_error(errormsg=acl)
+
+                # We will set get privileges from acl sql so we don't need
+                # it from properties sql
+                column['attacl'] = []
+
+                for row in acl['rows']:
+                    priv = parse_priv_from_db(row)
+                    column.setdefault(row['deftype'], []).append(priv)
+
+                # we are receiving request when in edit mode
+                # we will send filtered types related to current type
+                present_type = column['cltype']
+
+                type_id = column['atttypid']
+
+                fulltype = self.get_full_type(
+                    column['typnspname'], column['typname'],
+                    column['isdup'], column['attndims'], column['atttypmod']
+                )
+
+                length = False
+                precision = False
+                if 'elemoid' in column:
+                    length, precision, typeval = \
+                        self.get_length_precision(column['elemoid'])
+
+                # Set length and precision to None
+                column['attlen'] = None
+                column['attprecision'] = None
+
+                # If we have length & precision both
+                if length and precision:
+                    matchObj = re.search(r'(\d+),(\d+)', fulltype)
+                    if matchObj:
+                        column['attlen'] = matchObj.group(1)
+                        column['attprecision'] = matchObj.group(2)
+                elif length:
+                    # If we have length only
+                    matchObj = re.search(r'(\d+)', fulltype)
+                    if matchObj:
+                        column['attlen'] = matchObj.group(1)
+                        column['attprecision'] = None
+
+
+                SQL = render_template("/".join([self.column_template_path,
+                                                'is_referenced.sql']),
+                                      tid=tid, clid=column['attnum'])
+
+                status, is_reference = self.conn.execute_scalar(SQL)
+
+                edit_types_list = list()
+                # We will need present type in edit mode
+
+                if column['typnspname'] == "pg_catalog" \
+                        or column['typnspname'] == "public":
+                    edit_types_list.append(present_type)
+                else:
+                    t = self.qtTypeIdent(self.conn, column['typnspname'],
+                                         present_type)
+                    edit_types_list.append(t)
+                    column['cltype'] = t
+
+                if int(is_reference) == 0:
+                    SQL = render_template("/".join([self.column_template_path,
+                                                    'edit_mode_types.sql']),
+                                          type_id=type_id)
+                    status, rset = self.conn.execute_2darray(SQL)
+
+                    for row in rset['rows']:
+                        edit_types_list.append(row['typname'])
+                else:
+                    edit_types_list.append(present_type)
+
+                column['edit_types'] = edit_types_list
+                column['cltype'] = DataTypeReader.parse_type_name(column['cltype'])
+
+                if 'indkey' in column:
+                    # Current column
+                    attnum = str(column['attnum'])
+
+                    # Single/List of primary key column(s)
+                    indkey = str(column['indkey'])
+
+                    # We will check if column is in primary column(s)
+                    if attnum in indkey.split(" "):
+                        column['is_primary_key'] = True
+                    else:
+                        column['is_primary_key'] = False
+
+        return data
+
+    def _index_constraints_formatter(self, did, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for index constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        index_constraints = {
+            'p': 'primary_key', 'u': 'unique_constraint'
+        }
+
+        for ctype in index_constraints.keys():
+            data[index_constraints[ctype]] = []
+
+            sql = render_template("/".join([self.index_constraint_template_path,
+                                            'properties.sql']),
+                                  did=did, tid=tid,
+                                  constraint_type=ctype)
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            for row in res['rows']:
+                result = row
+                sql = render_template(
+                    "/".join([self.index_constraint_template_path,
+                              'get_constraint_cols.sql']),
+                    cid=row['oid'],
+                    colcnt=row['indnatts'])
+                status, res = self.conn.execute_dict(sql)
+
+                if not status:
+                    return internal_server_error(errormsg=res)
+
+                columns = []
+                for r in res['rows']:
+                    columns.append({"column": r['column'].strip('"')})
+
+                result['columns'] = columns
+
+                # If not exists then create list and/or append into
+                # existing list [ Adding into main data dict]
+                data.setdefault(index_constraints[ctype], []).append(result)
+
+        return data
+
+    def _foreign_key_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for foreign key constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        sql = render_template("/".join([self.foreign_key_template_path,
+                                        'properties.sql']),
+                              tid=tid)
+
+        status, result = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=result)
+
+        for fk in result['rows']:
+
+            sql = render_template("/".join([self.foreign_key_template_path,
+                                            'get_constraint_cols.sql']),
+                                  tid=tid,
+                                  keys=zip(fk['confkey'], fk['conkey']),
+                                  confrelid=fk['confrelid'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            cols = []
+            for row in res['rows']:
+                columns.append({"local_column": row['conattname'],
+                                "references": fk['confrelid'],
+                                "referenced": row['confattname']})
+                cols.append(row['conattname'])
+
+            fk['columns'] = columns
+
+            SQL = render_template("/".join([self.foreign_key_template_path,
+                                            'get_parent.sql']),
+                                  tid=fk['columns'][0]['references'])
+
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            fk['remote_schema'] = rset['rows'][0]['schema']
+            fk['remote_table'] = rset['rows'][0]['table']
+
+            coveringindex = self.search_coveringindex(tid, cols)
+
+            fk['coveringindex'] = coveringindex
+            if coveringindex:
+                fk['autoindex'] = True
+                fk['hasindex'] = True
+            else:
+                fk['autoindex'] = False
+                fk['hasindex'] = False
+            # If not exists then create list and/or append into
+            # existing list [ Adding into main data dict]
+            data.setdefault('foreign_key', []).append(fk)
+
+        return data
+
+    def _check_constraint_formatter(self, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for check constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        SQL = render_template("/".join([self.check_constraint_template_path,
+                                        'properties.sql']),
+                              tid=tid)
+
+        status, res = self.conn.execute_dict(SQL)
+
+        if not status:
+            return internal_server_error(errormsg=res)
+        # If not exists then create list and/or append into
+        # existing list [ Adding into main data dict]
+
+        data['check_constraint'] = res['rows']
+
+        return data
+
+    def _exclusion_constraint_formatter(self, did, tid, data):
+        """
+        Args:
+            tid: Table OID
+            data: dict of query result
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format for exclusion constraint node
+        """
+
+        # We will fetch all the index constraints for the table
+        sql = render_template("/".join([self.exclusion_constraint_template_path,
+                                        'properties.sql']),
+                              did=did, tid=tid)
+
+        status, result = self.conn.execute_dict(sql)
+
+        if not status:
+            return internal_server_error(errormsg=result)
+
+        for ex in result['rows']:
+
+            sql = render_template("/".join(
+                [self.exclusion_constraint_template_path,
+                 'get_constraint_cols.sql']),
+                cid=ex['oid'],
+                colcnt=ex['indnatts'])
+
+            status, res = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            columns = []
+            for row in res['rows']:
+                if row['options'] & 1:
+                    order = False
+                    nulls_order = True if (row['options'] & 2) else False
+                else:
+                    order = True
+                    nulls_order = True if (row['options'] & 2) else False
+
+                columns.append({"column": row['coldef'].strip('"'),
+                                "oper_class": row['opcname'],
+                                "order": order,
+                                "nulls_order": nulls_order,
+                                "operator": row['oprname'],
+                                "col_type": row['datatype']
+                                })
+
+            ex['columns'] = columns
+            # If not exists then create list and/or append into
+            # existing list [ Adding into main data dict]
+            data.setdefault('exclude_constraint', []).append(ex)
+
+        return data
+
+    def _formatter(self, did, scid, tid, data):
+        """
+        Args:
+            data: dict of query result
+            scid: schema oid
+            tid: table oid
+
+        Returns:
+            It will return formatted output of query result
+            as per client model format
+        """
+        # Need to format security labels according to client js collection
+        if 'seclabels' in data and data['seclabels'] is not None:
+            seclabels = []
+            for seclbls in data['seclabels']:
+                k, v = seclbls.split('=')
+                seclabels.append({'provider': k, 'label': v})
+
+            data['seclabels'] = seclabels
+
+        # We need to parse & convert ACL coming from database to json format
+        SQL = render_template("/".join([self.table_template_path, 'acl.sql']),
+                              tid=tid, scid=scid)
+        status, acl = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=acl)
+
+        # We will set get privileges from acl sql so we don't need
+        # it from properties sql
+        for row in acl['rows']:
+            priv = parse_priv_from_db(row)
+            if row['deftype'] in data:
+                data[row['deftype']].append(priv)
+            else:
+                data[row['deftype']] = [priv]
+
+        # We will add Auto vacuum defaults with out result for grid
+        data['vacuum_table'] = self.parse_vacuum_data(self.conn, data, 'table')
+        data['vacuum_toast'] = self.parse_vacuum_data(self.conn, data, 'toast')
+
+        # Fetch columns for the table logic
+        #
+        # 1) Check if of_type and inherited tables are present?
+        # 2) If yes then Fetch all the columns for of_type and inherited tables
+        # 3) Add columns in columns collection
+        # 4) Find all the columns for tables and filter out columns which are
+        #   not inherited from any table & format them one by one
+
+        # Get of_type table columns and add it into columns dict
+        if data['typname']:
+            SQL = render_template("/".join([self.table_template_path,
+                                            'get_columns_for_table.sql']),
+                                  tname=data['typname'])
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+            data['columns'] = res['rows']
+
+        # Get inherited table(s) columns and add it into columns dict
+        elif data['coll_inherits'] and len(data['coll_inherits']) > 0:
+            columns = []
+            # Return all tables which can be inherited & do not show
+            # system columns
+            SQL = render_template("/".join([self.table_template_path,
+                                            'get_inherits.sql']),
+                                  show_system_objects=False
+                                  )
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                if row['inherits'] in data['coll_inherits']:
+                    # Fetch columns using inherited table OID
+                    SQL = render_template("/".join(
+                        [self.table_template_path,
+                         'get_columns_for_table.sql']),
+                        tid=row['oid']
+                    )
+                    status, res = self.conn.execute_dict(SQL)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+                    columns.extend(res['rows'][:])
+            data['columns'] = columns
+
+        # We will fetch all the columns for the table using
+        # columns properties.sql, so we need to set template path
+        SQL = render_template("/".join([self.column_template_path,
+                                        'properties.sql']),
+                              tid=tid,
+                              show_sys_objects=False
+                              )
+
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+        all_columns = res['rows']
+
+        # Filter inherited columns from all columns
+        if 'columns' in data and len(data['columns']) > 0 \
+                and len(all_columns) > 0:
+            for row in data['columns']:
+                for i, col in enumerate(all_columns):
+                    # If both name are same then remove it
+                    # as it is inherited from other table
+                    if col['name'] == row['name']:
+                        # Remove same column from all_columns as
+                        # already have it columns collection
+                        del all_columns[i]
+
+            # If any column is added then update columns collection
+            if len(all_columns) > 0:
+                data['columns'] += all_columns
+        # If no inherited columns found then add all columns
+        elif len(all_columns) > 0:
+            data['columns'] = all_columns
+
+        if 'columns' in data and len(data['columns']) > 0:
+            data = self._columns_formatter(tid, data)
+
+        # Here we will add constraint in our output
+        data = self._index_constraints_formatter(did, tid, data)
+        data = self._foreign_key_formatter(tid, data)
+        data = self._check_constraint_formatter(tid, data)
+        data = self._exclusion_constraint_formatter(did, tid, data)
+
+        return data
+
+    @staticmethod
+    def _cltype_formatter(data_type):
+        """
+
+        Args:
+            data_type: Type string
+
+        Returns:
+            We need to remove [] from type and append it
+            after length/precision so we will send flag for
+            sql template
+        """
+        if '[]' in data_type:
+            return data_type[:-2], True
+        else:
+            return data_type, False
+
+    def get_table_dependents(self, tid):
+        """
+        This function get the dependents and return ajax response
+        for the table node.
+
+        Args:
+            tid: Table ID
+        """
+        # Specific condition for column which we need to append
+        where = "WHERE dep.refobjid={0}::OID".format(tid)
+
+        dependents_result = self.get_dependents(
+            self.conn, tid
+        )
+
+        # Specific sql to run againt column to fetch dependents
+        SQL = render_template("/".join([self.table_template_path,
+                                        'depend.sql']), where=where)
+
+        status, res = self.conn.execute_dict(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        for row in res['rows']:
+            ref_name = row['refname']
+            if ref_name is None:
+                continue
+
+            dep_type = ''
+            dep_str = row['deptype']
+            if dep_str == 'a':
+                dep_type = 'auto'
+            elif dep_str == 'n':
+                dep_type = 'normal'
+            elif dep_str == 'i':
+                dep_type = 'internal'
+
+            dependents_result.append({'type': 'sequence', 'name': ref_name,
+                                      'field': dep_type})
+
+        return ajax_response(
+            response=dependents_result,
+            status=200
+        )
+
+    def get_table_dependencies(self, tid):
+        """
+        This function get the dependencies and return ajax response
+        for the table node.
+
+        Args:
+            tid: Table ID
+
+        """
+        dependencies_result = self.get_dependencies(
+            self.conn, tid
+        )
+
+        return ajax_response(
+            response=dependencies_result,
+            status=200
+        )
+
+    def get_table_statistics(self, scid, tid):
+        """
+        Statistics
+
+        Args:
+            scid: Schema Id
+            tid: Table Id
+
+        Returns the statistics for a particular table if tid is specified,
+        otherwise it will return statistics for all the tables in that
+        schema.
+        """
+
+        # Fetch schema name
+        status, schema_name = self.conn.execute_scalar(
+            render_template(
+                "/".join([self.table_template_path, 'get_schema.sql']),
+                conn=self.conn, scid=scid
+            )
+        )
+        if not status:
+            return internal_server_error(errormsg=schema_name)
+
+        if tid is None:
+            status, res = self.conn.execute_dict(
+                render_template(
+                    "/".join([self.table_template_path,
+                              'coll_table_stats.sql']), conn=self.conn,
+                    schema_name=schema_name
+                )
+            )
+        else:
+            # For Individual table stats
+
+            # Check if pgstattuple extension is already created?
+            # if created then only add extended stats
+            status, is_pgstattuple = self.conn.execute_scalar("""
+            SELECT (count(extname) > 0) AS is_pgstattuple
+            FROM pg_extension
+            WHERE extname='pgstattuple'
+            """)
+            if not status:
+                return internal_server_error(errormsg=is_pgstattuple)
+
+            # Fetch Table name
+            status, table_name = self.conn.execute_scalar(
+                render_template(
+                    "/".join([self.table_template_path, 'get_table.sql']),
+                    conn=self.conn, scid=scid, tid=tid
+                )
+            )
+            if not status:
+                return internal_server_error(errormsg=table_name)
+
+            status, res = self.conn.execute_dict(
+                render_template(
+                    "/".join([self.table_template_path, 'stats.sql']),
+                    conn=self.conn, schema_name=schema_name,
+                    table_name=table_name,
+                    is_pgstattuple=is_pgstattuple, tid=tid
+                )
+            )
+
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return make_json_response(
+            data=res,
+            status=200
+        )
+
+    def get_reverse_engineered_sql(self, did, scid, tid, main_sql, data):
+        """
+        This function will creates reverse engineered sql for
+        the table object
+
+         Args:
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           main_sql: List contains all the reversed engineered sql
+           data: Table's Data
+        """
+        """
+        #####################################
+        # 1) Reverse engineered sql for TABLE
+        #####################################
+        """
+
+        # Table & Schema declaration so that we can use them in child nodes
+        schema = data['schema']
+        table = data['name']
+
+        data = self._formatter(did, scid, tid, data)
+
+        # Now we have all lis of columns which we need
+        # to include in our create definition, Let's format them
+        if 'columns' in data:
+            for c in data['columns']:
+                if 'attacl' in c:
+                    c['attacl'] = parse_priv_to_db(c['attacl'], self.column_acl)
+
+                # check type for '[]' in it
+                if 'cltype' in c:
+                    c['cltype'], c['hasSqrBracket'] = \
+                        self._cltype_formatter(c['cltype'])
+
+        sql_header = u"-- Table: {0}\n\n-- ".format(
+            self.qtIdent(self.conn, data['schema'], data['name']))
+
+        sql_header += render_template("/".join([self.table_template_path,
+                                                'delete.sql']),
+                                      data=data, conn=self.conn)
+
+        sql_header = sql_header.strip('\n')
+        sql_header += '\n'
+
+        # Add into main sql
+        main_sql.append(sql_header)
+
+        # Parse privilege data
+        if 'relacl' in data:
+            data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
+
+        # if table is partitions then
+        if 'relispartition' in data and data['relispartition']:
+            table_sql = render_template("/".join([self.partition_template_path,
+                                                  'create.sql']),
+                                        data=data, conn=self.conn)
+        else:
+            table_sql = render_template("/".join([self.table_template_path,
+                                                  'create.sql']),
+                                        data=data, conn=self.conn)
+
+        # Add into main sql
+        table_sql = re.sub('\n{2,}', '\n\n', table_sql)
+        main_sql.append(table_sql.strip('\n'))
+
+        """
+        ######################################
+        # 2) Reverse engineered sql for INDEX
+        ######################################
+        """
+
+        SQL = render_template("/".join([self.index_template_path,
+                                        'nodes.sql']), tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+
+            SQL = render_template("/".join([self.index_template_path,
+                                            'properties.sql']),
+                                  did=did, tid=tid, idx=row['oid'],
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+            # Adding parent into data dict, will be using it while creating sql
+            data['schema'] = schema
+            data['table'] = table
+            # We also need to fecth columns of index
+            SQL = render_template("/".join([self.index_template_path,
+                                            'column_details.sql']),
+                                  idx=row['oid'])
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            # 'attdef' comes with quotes from query so we need to strip them
+            # 'options' we need true/false to render switch
+            # ASC(false)/DESC(true)
+            columns = []
+            cols = []
+            for col_row in rset['rows']:
+                # We need all data as collection for ColumnsModel
+                cols_data = {
+                    'colname': col_row['attdef'].strip('"'),
+                    'collspcname': col_row['collnspname'],
+                    'op_class': col_row['opcname'],
+                }
+                if col_row['options'][0] == 'DESC':
+                    cols_data['sort_order'] = True
+                columns.append(cols_data)
+
+                # We need same data as string to display in properties window
+                # If multiple column then separate it by colon
+                cols_str = col_row['attdef']
+                if col_row['collnspname']:
+                    cols_str += ' COLLATE ' + col_row['collnspname']
+                if col_row['opcname']:
+                    cols_str += ' ' + col_row['opcname']
+                if col_row['options'][0] == 'DESC':
+                    cols_str += ' DESC'
+                cols.append(cols_str)
+
+            # Push as collection
+            data['columns'] = columns
+            # Push as string
+            data['cols'] = ', '.join(cols)
+
+            sql_header = u"\n-- Index: {0}\n\n-- ".format(data['name'])
+
+            sql_header += render_template("/".join([self.index_template_path,
+                                                    'delete.sql']),
+                                          data=data, conn=self.conn)
+
+            index_sql = render_template("/".join([self.index_template_path,
+                                                  'create.sql']),
+                                        data=data, conn=self.conn)
+            index_sql += "\n"
+            index_sql += render_template("/".join([self.index_template_path,
+                                                   'alter.sql']),
+                                         data=data, conn=self.conn)
+
+            # Add into main sql
+            index_sql = re.sub('\n{2,}', '\n\n', index_sql)
+            main_sql.append(sql_header + '\n\n' + index_sql.strip('\n'))
+
+        """
+        ########################################
+        # 3) Reverse engineered sql for TRIGGERS
+        ########################################
+        """
+        SQL = render_template("/".join([self.trigger_template_path,
+                                        'nodes.sql']), tid=tid)
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            trigger_sql = ''
+
+            SQL = render_template("/".join([self.trigger_template_path,
+                                            'properties.sql']),
+                                  tid=tid, trid=row['oid'],
+                                  datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            data = dict(res['rows'][0])
+            # Adding parent into data dict, will be using it while creating sql
+            data['schema'] = schema
+            data['table'] = table
+
+            if data['tgnargs'] > 1:
+                # We know that trigger has more than 1 arguments,
+                # let's join them
+                data['tgargs'] = ', '.join(data['tgargs'])
+
+            if len(data['tgattr']) > 1:
+                columns = ', '.join(data['tgattr'].split(' '))
+
+                SQL = render_template("/".join([self.trigger_template_path,
+                                                'get_columns.sql']),
+                                      tid=tid, clist=columns)
+
+                status, rset = self.conn.execute_2darray(SQL)
+                if not status:
+                    return internal_server_error(errormsg=rset)
+                # 'tgattr' contains list of columns from table used in trigger
+                columns = []
+
+                for col_row in rset['rows']:
+                    columns.append({'column': col_row['name']})
+
+                data['columns'] = columns
+
+            data = trigger_definition(data)
+
+            sql_header = u"\n-- Trigger: {0}\n\n-- ".format(data['name'])
+
+            sql_header += render_template("/".join([self.trigger_template_path,
+                                                    'delete.sql']),
+                                          data=data, conn=self.conn)
+
+            # If the request for new object which do not have did
+            trigger_sql = render_template("/".join([self.trigger_template_path,
+                                                    'create.sql']),
+                                          data=data, conn=self.conn)
+
+            trigger_sql = sql_header + '\n\n' + trigger_sql.strip('\n')
+
+            # If trigger is disabled then add sql code for the same
+            if not data['is_enable_trigger']:
+                trigger_sql += '\n\n'
+                trigger_sql += render_template("/".join([
+                    self.trigger_template_path,
+                    'enable_disable_trigger.sql']),
+                    data=data, conn=self.conn)
+
+            # Add into main sql
+            trigger_sql = re.sub('\n{2,}', '\n\n', trigger_sql)
+            main_sql.append(trigger_sql)
+
+        """
+        #####################################
+        # 4) Reverse engineered sql for RULES
+        #####################################
+        """
+
+        SQL = render_template("/".join(
+            [self.rules_template_path, 'properties.sql']), tid=tid)
+
+        status, rset = self.conn.execute_2darray(SQL)
+        if not status:
+            return internal_server_error(errormsg=rset)
+
+        for row in rset['rows']:
+            rules_sql = '\n'
+            SQL = render_template("/".join(
+                [self.rules_template_path, 'properties.sql']
+            ), rid=row['oid'], datlastsysoid=self.datlastsysoid)
+
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            res_data = parse_rule_definition(res)
+            rules_sql += render_template("/".join(
+                [self.rules_template_path, 'create.sql']),
+                data=res_data, display_comments=True)
+
+            # Add into main sql
+            rules_sql = re.sub('\n{2,}', '\n\n', rules_sql)
+            main_sql.append(rules_sql)
+
+        """
+        ##########################################
+        # 5) Reverse engineered sql for PARTITIONS
+        ##########################################
+        """
+        if 'is_partitioned' in data and data['is_partitioned']:
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'nodes.sql']),
+                                  scid=scid, tid=tid)
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            sql_header = u"\n-- Partitions SQL"
+            partition_sql = ''
+            for row in rset['rows']:
+                part_data = dict()
+                part_data['partitioned_table_name'] = data['name']
+                part_data['parent_schema'] = data['schema']
+                part_data['schema'] = row['schema_name']
+                part_data['relispartition'] = True
+                part_data['name'] = row['name']
+                part_data['partition_value'] = row['partition_value']
+                part_data['is_partitioned'] = row ['is_partitioned']
+                part_data['partition_scheme'] = row['partition_scheme']
+
+                partition_sql += render_template("/".join(
+                    [self.partition_template_path, 'create.sql']),
+                    data=part_data, conn=self.conn)
+
+            # Add into main sql
+            partition_sql = re.sub('\n{2,}', '\n\n', partition_sql)
+            main_sql.append(sql_header + '\n\n' + partition_sql.strip('\n'))
+
+        sql = '\n'.join(main_sql)
+
+        return ajax_response(response=sql.strip('\n'))
+
+    def reset_statistics(self, scid, tid):
+        """
+        This function will reset statistics of table
+
+         Args:
+           scid: Schema ID
+           tid: Table ID
+        """
+        try:
+            SQL = render_template("/".join([self.table_template_path,
+                                            'reset_stats.sql']),
+                                  tid=tid)
+            status, res = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=res)
+
+            return make_json_response(
+                success=1,
+                info=gettext("Table statistics have been reset"),
+                data={
+                    'id': tid,
+                    'scid': scid
+                }
+            )
+
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def get_partition_scheme(self, data):
+        partition_scheme = None
+        if 'partition_type' in data \
+                and data['partition_type'] == 'range':
+            partition_scheme = 'RANGE ('
+        elif 'partition_type' in data \
+                and data['partition_type'] == 'list':
+            partition_scheme = 'LIST ('
+
+        for row in data['partition_keys']:
+            if row['key_type'] == 'column':
+                partition_scheme += self.qtIdent(
+                    self.conn, row['pt_column']) + ', '
+            elif row['key_type'] == 'expression':
+                partition_scheme += row['expression'] + ', '
+
+        # Remove extra space and comma
+        if len(data['partition_keys']) > 0:
+            partition_scheme = partition_scheme[:-2]
+        partition_scheme += ')'
+
+        return partition_scheme
+
+    @staticmethod
+    def validate_constrains(key, data):
+
+        if key == 'primary_key' or key == 'unique_constraint':
+            if 'columns' in data and len(data['columns']) > 0:
+                return True
+            else:
+                return False
+        elif key == 'foreign_key':
+            if 'oid' not in data:
+                for arg in ['columns']:
+                    if arg not in data:
+                        return False
+                    elif isinstance(data[arg], list) and len(data[arg]) < 1:
+                        return False
+
+                if 'autoindex' in data and data['autoindex'] and \
+                        ('coveringindex' not in data or
+                                                  data['coveringindex'] == ''):
+                    return False
+
+            return True
+
+        elif key == 'check_constraint':
+            for arg in ['consrc']:
+                if arg not in data or data[arg] == '':
+                    return False
+            return True
+
+        elif key == 'exclude_constraint':
+            pass
+
+        return True
+
+    @staticmethod
+    def check_and_convert_name_to_string(data):
+        """
+        This function will check and covert table to string incase
+        it is numeric
+
+        Args:
+            data: data dict
+
+        Returns:
+            Updated data dict
+        """
+        # For Python2, it can be int, long, float
+        if hasattr(str, 'decode'):
+            if isinstance(data['name'], (int, long, float)):
+                data['name'] = str(data['name'])
+        else:
+            # For Python3, it can be int, float
+            if isinstance(data['name'], (int, float)):
+                data['name'] = str(data['name'])
+        return data
+
+    def get_index_constraint_sql(self, did, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+        This function will generate modified sql for index constraints
+        (Primary Key & Unique)
+        """
+        sql = []
+        # We will fetch all the index constraints for the table
+        index_constraints = {
+            'p': 'primary_key', 'u': 'unique_constraint'
+        }
+
+        for ctype in index_constraints.keys():
+            # Check if constraint is in data
+            # If yes then we need to check for add/change/delete
+            if index_constraints[ctype] in data:
+                constraint = data[index_constraints[ctype]]
+                # If constraint(s) is/are deleted
+                if 'deleted' in constraint:
+                    for c in constraint['deleted']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+
+                        # Sql for drop
+                        sql.append(
+                            render_template("/".join(
+                                [self.index_constraint_template_path,
+                                 'delete.sql']),
+                                data=c, conn=self.conn).strip('\n')
+                        )
+
+                if 'changed' in constraint:
+                    for c in constraint['changed']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+
+                        properties_sql = render_template("/".join(
+                            [self.index_constraint_template_path, 'properties.sql']),
+                            did=did, tid=tid, cid=c['oid'], constraint_type=ctype)
+                        status, res = self.conn.execute_dict(properties_sql)
+                        if not status:
+                            return internal_server_error(errormsg=res)
+
+                        old_data = res['rows'][0]
+                        # Sql to update object
+                        sql.append(
+                            render_template("/".join([
+                                self.index_constraint_template_path,
+                                'update.sql']), data=c, o_data=old_data,
+                                conn=self.conn).strip('\n')
+                        )
+
+                if 'added' in constraint:
+                    for c in constraint['added']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+
+                        # Sql to add object
+                        if self.validate_constrains(index_constraints[ctype], c):
+                            sql.append(
+                                render_template(
+                                    "/".join([self.index_constraint_template_path,
+                                              'create.sql']),
+                                    data=c, conn=self.conn,
+                                    constraint_name='PRIMARY KEY'
+                                    if ctype == 'p' else 'UNIQUE'
+                                ).strip('\n')
+                            )
+                        else:
+                            sql.append(
+                                gettext(
+                                    '-- definition incomplete for {0} constraint'.format(index_constraints[ctype])
+                                )
+                            )
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_foreign_key_sql(self, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+        This function will generate modified sql for foreign key
+        """
+        sql = []
+        # Check if constraint is in data
+        # If yes then we need to check for add/change/delete
+        if 'foreign_key' in data:
+            constraint = data['foreign_key']
+            # If constraint(s) is/are deleted
+            if 'deleted' in constraint:
+                for c in constraint['deleted']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql for drop
+                    sql.append(
+                        render_template("/".join(
+                            [self.foreign_key_template_path,
+                             'delete.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                    )
+
+            if 'changed' in constraint:
+                for c in constraint['changed']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    properties_sql = render_template("/".join(
+                        [self.foreign_key_template_path, 'properties.sql']),
+                        tid=tid, cid=c['oid'])
+                    status, res = self.conn.execute_dict(properties_sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+                    old_data = res['rows'][0]
+                    # Sql to update object
+                    sql.append(
+                        render_template("/".join([
+                            self.foreign_key_template_path,
+                            'update.sql']), data=c, o_data=old_data,
+                            conn=self.conn).strip('\n')
+                    )
+
+                    if not self.validate_constrains('foreign_key', c):
+                        sql.append(
+                            gettext(
+                                '-- definition incomplete for foreign_key constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    if 'columns' in c:
+                        cols = []
+                        for col in c['columns']:
+                            cols.append(col['local_column'])
+
+                        coveringindex = self.search_coveringindex(tid, cols)
+
+                        if coveringindex is None and 'autoindex' in c and c['autoindex'] and \
+                                ('coveringindex' in c and
+                                         c['coveringindex'] != ''):
+                            sql.append(render_template(
+                                "/".join([self.foreign_key_template_path, 'create_index.sql']),
+                                data=c, conn=self.conn).strip('\n')
+                                       )
+
+            if 'added' in constraint:
+                for c in constraint['added']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql to add object
+                    # Columns
+
+                    if not self.validate_constrains('foreign_key', c):
+                        sql.append(
+                            gettext(
+                                '-- definition incomplete for foreign_key constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    SQL = render_template("/".join([self.foreign_key_template_path,
+                                                    'get_parent.sql']),
+                                          tid=c['columns'][0]['references'])
+                    status, rset = self.conn.execute_2darray(SQL)
+                    if not status:
+                        return internal_server_error(errormsg=rset)
+
+                    c['remote_schema'] = rset['rows'][0]['schema']
+                    c['remote_table'] = rset['rows'][0]['table']
+
+                    sql.append(
+                        render_template(
+                            "/".join([self.foreign_key_template_path,
+                                      'create.sql']),
+                            data=c, conn=self.conn
+                        ).strip('\n')
+                    )
+
+                    if c['autoindex']:
+                        sql.append(
+                            render_template(
+                                "/".join([self.foreign_key_template_path,
+                                          'create_index.sql']),
+                                data=c, conn=self.conn).strip('\n')
+                        )
+
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_check_constraint_sql(self, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+          This function will generate modified sql for check constraint
+        """
+        sql = []
+        # Check if constraint is in data
+        # If yes then we need to check for add/change/delete
+        if 'check_constraint' in data:
+            constraint = data['check_constraint']
+            # If constraint(s) is/are deleted
+            if 'deleted' in constraint:
+                for c in constraint['deleted']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql for drop
+                    sql.append(
+                        render_template("/".join(
+                            [self.check_constraint_template_path,
+                             'delete.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                    )
+
+            if 'changed' in constraint:
+                for c in constraint['changed']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    properties_sql = render_template("/".join(
+                        [self.check_constraint_template_path, 'properties.sql']),
+                        tid=tid, cid=c['oid'])
+                    status, res = self.conn.execute_dict(properties_sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+                    old_data = res['rows'][0]
+                    # Sql to update object
+                    sql.append(
+                        render_template("/".join([
+                            self.check_constraint_template_path,
+                            'update.sql']), data=c, o_data=old_data,
+                            conn=self.conn).strip('\n')
+                    )
+
+            if 'added' in constraint:
+                for c in constraint['added']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    if not self.validate_constrains('check_constraint', c):
+                        sql.append(
+                            gettext(
+                                '-- definition incomplete for check_constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    sql.append(
+                        render_template(
+                            "/".join([self.check_constraint_template_path,
+                                      'create.sql']),
+                            data=c, conn=self.conn
+                        ).strip('\n')
+                    )
+
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return '\n\n'.join(sql)
+        else:
+            return None
+
+    def get_exclusion_constraint_sql(self, did, tid, data):
+        """
+         Args:
+           tid: Table ID
+           data: data dict coming from the client
+
+        Returns:
+          This function will generate modified sql for exclusion constraint
+        """
+        sql = []
+        # Check if constraint is in data
+        # If yes then we need to check for add/change/delete
+        if 'exclude_constraint' in data:
+            constraint = data['exclude_constraint']
+            # If constraint(s) is/are deleted
+            if 'deleted' in constraint:
+                for c in constraint['deleted']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    # Sql for drop
+                    sql.append(
+                        render_template("/".join(
+                            [self.exclusion_constraint_template_path,
+                             'delete.sql']),
+                            data=c, conn=self.conn).strip('\n')
+                    )
+
+            if 'changed' in constraint:
+                for c in constraint['changed']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    properties_sql = render_template("/".join(
+                        [self.exclusion_constraint_template_path, 'properties.sql']),
+                        did=did, tid=tid, cid=c['oid'])
+                    status, res = self.conn.execute_dict(properties_sql)
+                    if not status:
+                        return internal_server_error(errormsg=res)
+
+                    old_data = res['rows'][0]
+                    # Sql to update object
+                    sql.append(
+                        render_template("/".join([
+                            self.exclusion_constraint_template_path,
+                            'update.sql']), data=c, o_data=old_data,
+                            conn=self.conn).strip('\n')
+                    )
+
+            if 'added' in constraint:
+                for c in constraint['added']:
+                    c['schema'] = data['schema']
+                    c['table'] = data['name']
+
+                    if not self.validate_constrains('exclude_constraint', c):
+                        sql.append(
+                            gettext(
+                                '-- definition incomplete for exclusion_constraint'
+                            )
+                        )
+                        return '\n\n'.join(sql)
+
+                    sql.append(
+                        render_template(
+                            "/".join([self.exclusion_constraint_template_path,
+                                      'create.sql']),
+                            data=c, conn=self.conn
+                        ).strip('\n')
+                    )
+
+        if len(sql) > 0:
+            # Join all the sql(s) as single string
+            return u'\n\n'.join(sql)
+        else:
+            return None
+
+    def get_sql(self, did, scid, tid, data, res):
+        """
+        This function will generate create/update sql from model data
+        coming from client
+        """
+        if tid is not None:
+            old_data = res['rows'][0]
+            old_data = self._formatter(did, scid, tid, old_data)
+
+            # We will convert privileges coming from client required
+            if 'relacl' in data:
+                for mode in ['added', 'changed', 'deleted']:
+                    if mode in data['relacl']:
+                        data['relacl'][mode] = parse_priv_to_db(
+                            data['relacl'][mode], self.acl
+                        )
+
+            # If name is not present in request data
+            if 'name' not in data:
+                data['name'] = old_data['name']
+
+            data = BaseTableView.check_and_convert_name_to_string(data)
+
+            # If name if not present
+            if 'schema' not in data:
+                data['schema'] = old_data['schema']
+
+            # Filter out new tables from list, we will send complete list
+            # and not newly added tables in the list from client
+            # so we will filter new tables here
+            if 'coll_inherits' in data:
+                p_len = len(old_data['coll_inherits'])
+                c_len = len(data['coll_inherits'])
+                # If table(s) added
+                if c_len > p_len:
+                    data['coll_inherits_added'] = list(
+                        set(data['coll_inherits']) - set(old_data['coll_inherits'])
+                    )
+                # If table(s)removed
+                elif c_len < p_len:
+                    data['coll_inherits_removed'] = list(
+                        set(old_data['coll_inherits']) - set(data['coll_inherits'])
+                    )
+                # Safe side verification,In case it happens..
+                # If user removes and adds same number of table
+                # eg removed one table and added one new table
+                elif c_len == p_len:
+                    data['coll_inherits_added'] = list(
+                        set(data['coll_inherits']) - set(old_data['coll_inherits'])
+                    )
+                    data['coll_inherits_removed'] = list(
+                        set(old_data['coll_inherits']) - set(data['coll_inherits'])
+                    )
+
+            SQL = render_template("/".join([self.table_template_path, 'update.sql']),
+                                  o_data=old_data, data=data, conn=self.conn)
+            # Removes training new lines
+            SQL = SQL.strip('\n') + '\n\n'
+
+            # Parse/Format columns & create sql
+            if 'columns' in data:
+                # Parse the data coming from client
+                data = self._parse_format_columns(data, mode='edit')
+
+                columns = data['columns']
+                column_sql = '\n'
+
+                # If column(s) is/are deleted
+                if 'deleted' in columns:
+                    for c in columns['deleted']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+                        # Sql for drop column
+                        if 'inheritedfrom' not in c:
+                            column_sql += render_template("/".join(
+                                [self.column_template_path, 'delete.sql']),
+                                data=c, conn=self.conn).strip('\n') + '\n\n'
+
+                # If column(s) is/are changed
+                # Here we will be needing previous properties of column
+                # so that we can compare & update it
+                if 'changed' in columns:
+                    for c in columns['changed']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+                        if 'attacl' in c:
+                            c['attacl'] = parse_priv_to_db(c['attacl'],
+                                                           self.column_acl)
+
+                        properties_sql = render_template("/".join([self.column_template_path,
+                                                                   'properties.sql']),
+                                                         tid=tid,
+                                                         clid=c['attnum'],
+                                                         show_sys_objects=self.blueprint.show_system_objects
+                                                         )
+
+                        status, res = self.conn.execute_dict(properties_sql)
+                        if not status:
+                            return internal_server_error(errormsg=res)
+                        old_data = res['rows'][0]
+
+                        old_data['cltype'], old_data['hasSqrBracket'] = self._cltype_formatter(old_data['cltype'])
+                        old_data = BaseTableView.convert_length_precision_to_string(old_data)
+
+                        fulltype = self.get_full_type(
+                            old_data['typnspname'], old_data['typname'],
+                            old_data['isdup'], old_data['attndims'], old_data['atttypmod']
+                        )
+
+                        # If we have length & precision both
+                        matchObj = re.search(r'(\d+),(\d+)', fulltype)
+                        if matchObj:
+                            old_data['attlen'] = int(matchObj.group(1))
+                            old_data['attprecision'] = int(matchObj.group(2))
+                        else:
+                            # If we have length only
+                            matchObj = re.search(r'(\d+)', fulltype)
+                            if matchObj:
+                                old_data['attlen'] = int(matchObj.group(1))
+                                old_data['attprecision'] = None
+                            else:
+                                old_data['attlen'] = None
+                                old_data['attprecision'] = None
+
+                        old_data['cltype'] = DataTypeReader.parse_type_name(old_data['cltype'])
+
+                        # Sql for alter column
+                        if 'inheritedfrom' not in c:
+                            column_sql += render_template("/".join(
+                                [self.column_template_path, 'update.sql']),
+                                data=c, o_data=old_data, conn=self.conn).strip('\n') + '\n\n'
+
+                # If column(s) is/are added
+                if 'added' in columns:
+                    for c in columns['added']:
+                        c['schema'] = data['schema']
+                        c['table'] = data['name']
+                        # Sql for create column
+                        if 'attacl' in c:
+                            c['attacl'] = parse_priv_to_db(c['attacl'],
+                                                           self.column_acl)
+
+                        c = BaseTableView.convert_length_precision_to_string(c)
+
+                        if 'inheritedfrom' not in c:
+                            column_sql += render_template("/".join(
+                                [self.column_template_path, 'create.sql']),
+                                data=c, conn=self.conn).strip('\n') + '\n\n'
+
+                # Combine all the SQL together
+                SQL += column_sql.strip('\n')
+
+            # Check for partitions
+            if 'partitions' in data:
+                partitions = data['partitions']
+                partitions_sql = '\n'
+
+                # If partition(s) is/are deleted
+                if 'deleted' in partitions:
+                    for row in partitions['deleted']:
+                        temp_data = dict()
+                        schema_name, table_name = \
+                            self.get_schema_and_table_name(row['oid'])
+
+                        temp_data['parent_schema'] = old_data['schema']
+                        temp_data['partitioned_table_name'] = old_data['name']
+                        temp_data['schema'] = schema_name
+                        temp_data['name'] = table_name
+
+                        # Sql for detach partition
+                        partitions_sql += render_template("/".join(
+                            [self.partition_template_path, 'detach.sql']),
+                            data=temp_data, conn=self.conn).strip('\n') + '\n\n'
+
+                # If partition(s) is/are added
+                if 'added' in partitions:
+                    temp_data = dict()
+                    temp_data['schema'] = old_data['schema']
+                    temp_data['name'] = old_data['name']
+                    # get the partition type
+                    temp_data['partition_type'] = \
+                        old_data['partition_scheme'].split()[0].lower()
+                    temp_data['partitions'] = partitions['added']
+
+                    partitions_sql += \
+                        self.get_partitions_sql(temp_data).strip('\n') + '\n\n'
+
+                # Combine all the SQL together
+                SQL += partitions_sql.strip('\n')
+
+            # Check if index constraints are added/changed/deleted
+            index_constraint_sql = self.get_index_constraint_sql(did, tid, data)
+            # If we have index constraint sql then ad it in main sql
+            if index_constraint_sql is not None:
+                SQL += '\n' + index_constraint_sql
+
+            # Check if foreign key(s) is/are added/changed/deleted
+            foreign_key_sql = self.get_foreign_key_sql(tid, data)
+            # If we have foreign key sql then ad it in main sql
+            if foreign_key_sql is not None:
+                SQL += '\n' + foreign_key_sql
+
+            # Check if check constraint(s) is/are added/changed/deleted
+            check_constraint_sql = self.get_check_constraint_sql(tid, data)
+            # If we have check constraint sql then ad it in main sql
+            if check_constraint_sql is not None:
+                SQL += '\n' + check_constraint_sql
+
+            # Check if exclusion constraint(s) is/are added/changed/deleted
+            exclusion_constraint_sql = self.get_exclusion_constraint_sql(did, tid, data)
+            # If we have check constraint sql then ad it in main sql
+            if exclusion_constraint_sql is not None:
+                SQL += '\n' + exclusion_constraint_sql
+
+        else:
+            res = None
+            required_args = [
+                'name'
+            ]
+
+            for arg in required_args:
+                if arg not in data:
+                    return gettext('-- definition incomplete')
+
+            # validate constraint data.
+            for key in ['primary_key', 'unique_constraint',
+                        'foreign_key', 'check_constraint',
+                        'exclude_constraint']:
+                if key in data and len(data[key]) > 0:
+                    for constraint in data[key]:
+                        if not self.validate_constrains(key, constraint):
+                            return gettext(
+                                '-- definition incomplete for {0}'.format(key)
+                            )
+
+            # We will convert privileges coming from client required
+            # in server side format
+            if 'relacl' in data:
+                data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
+
+            # Parse & format columns
+            data = self._parse_format_columns(data)
+            data = BaseTableView.check_and_convert_name_to_string(data)
+
+            if 'foreign_key' in data:
+                for c in data['foreign_key']:
+                    SQL = render_template("/".join(
+                        [self.foreign_key_template_path,
+                         'get_parent.sql']),
+                        tid=c['columns'][0]['references'])
+                    status, rset = self.conn.execute_2darray(SQL)
+                    if not status:
+                        return internal_server_error(errormsg=rset)
+
+                    c['remote_schema'] = rset['rows'][0]['schema']
+                    c['remote_table'] = rset['rows'][0]['table']
+
+            partitions_sql = ''
+            if 'is_partitioned' in data and data['is_partitioned']:
+                data['relkind'] = 'p'
+                # create partition scheme
+                data['partition_scheme'] = self.get_partition_scheme(data)
+                partitions_sql = self.get_partitions_sql(data)
+
+            SQL = render_template("/".join([self.table_template_path,
+                                            'create.sql']),
+                                  data=data, conn=self.conn)
+
+            # Append SQL for partitions
+            SQL += '\n' + partitions_sql
+
+        SQL = re.sub('\n{2,}', '\n\n', SQL)
+        SQL = SQL.strip('\n')
+
+        return SQL, data['name'] if 'name' in data else old_data['name']
+
+    def update(self, gid, sid, did, scid, tid, data, res, parent_id=None):
+        """
+        This function will update an existing table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+           data: Data to update
+           res: Table properties
+           parent_id: parent table id if current table is partition of parent
+                    table else none
+        """
+        try:
+            relkind = res['relkind'] if 'relkind' in res else ''
+            SQL, name = self.get_sql(did, scid, tid, data, res)
+
+            SQL = SQL.strip('\n').strip(' ')
+            status, rest = self.conn.execute_scalar(SQL)
+            if not status:
+                return internal_server_error(errormsg=rest)
+
+            SQL = render_template("/".join([self.table_template_path,
+                                  'get_schema_oid.sql']), tid=tid)
+            status, rest = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rest)
+
+            if not parent_id:
+                parent_id = scid
+
+            return jsonify(
+                node=self.blueprint.generate_browser_node(
+                    tid,
+                    parent_id,
+                    name,
+                    icon="icon-partition" if ('is_partitioned' in res['rows'][0] and
+                                             res['rows'][0]['is_partitioned']) or
+                                             self.node_type == 'partition' else "icon-table",
+                    is_partitioned=True if relkind == 'p' else False,
+                    parent_schema_id=scid,
+                    schema_id=rest['rows'][0]['scid'],
+                    schema_name=rest['rows'][0]['nspname']
+                )
+            )
+        except Exception as e:
+            return internal_server_error(errormsg=str(e))
+
+    def properties(self, gid, sid, did, scid, tid, res):
+        """
+        This function will show the properties of the selected table node.
+
+        Args:
+            gid: Server Group ID
+            sid: Server ID
+            did:  Database ID
+            scid: Schema ID
+            scid: Schema ID
+            tid: Table ID
+            res: Table/Partition table properties
+
+        Returns:
+            JSON of selected table node
+        """
+        data = res['rows'][0]
+
+        data['vacuum_settings_str'] = ""
+
+        if data['table_vacuum_settings_str'] is not None:
+            data['vacuum_settings_str'] += data[
+                'table_vacuum_settings_str'].replace(',', '\n')
+
+        if data['toast_table_vacuum_settings_str'] is not None:
+            data['vacuum_settings_str'] += '\n' + '\n'.join(
+                ['toast_' + setting for setting in data[
+                    'toast_table_vacuum_settings_str'
+                ].split(',')]
+            )
+        data['vacuum_settings_str'] = data[
+            'vacuum_settings_str'
+        ].replace("=", " = ")
+
+        data = self._formatter(did, scid, tid, data)
+
+        # Fetch partition of this table if it is partitioned table.
+        if 'is_partitioned' in data and data['is_partitioned']:
+            # get the partition type
+            data['partition_type'] = data['partition_scheme'].split()[0].lower()
+
+            partitions = []
+            SQL = render_template("/".join([self.partition_template_path,
+                                            'nodes.sql']),
+                                  scid=scid, tid=tid)
+            status, rset = self.conn.execute_2darray(SQL)
+            if not status:
+                return internal_server_error(errormsg=rset)
+
+            for row in rset['rows']:
+                partition_name = row['name']
+                # if schema name is different then display schema
+                # qualified name on UI.
+                if data['schema'] != row['schema_name']:
+                    partition_name = row['schema_name'] + '.' + row['name']
+
+                if data['partition_type'] == 'range':
+                    range_part = row['partition_value'].split(
+                            'FOR VALUES FROM (')[1].split(') TO')
+                    range_from = range_part[0]
+                    range_to = range_part[1][2:-1]
+
+                    partitions.append({
+                        'oid': row['oid'],
+                        'partition_name': partition_name,
+                        'values_from': range_from,
+                        'values_to': range_to
+                    })
+                else:
+                    range_part = \
+                        row['partition_value'].split('FOR VALUES IN (')[1]
+
+                    range_in = range_part[:-1]
+                    partitions.append({
+                        'oid': row['oid'],
+                        'partition_name': partition_name,
+                        'values_in': range_in
+                    })
+
+            data['partitions'] = partitions
+
+        return ajax_response(
+            response=data,
+            status=200
+        )
+
+    def get_partitions_sql(self, partitions):
+        """
+        This function will iterate all the partitions and create SQL.
+
+        :param partitions: List of partitions
+        """
+        sql = ''
+
+        for row in partitions['partitions']:
+            part_data = dict()
+            part_data['partitioned_table_name'] = partitions['name']
+            part_data['parent_schema'] = partitions['schema']
+
+            if 'is_attach' in row and row['is_attach']:
+                schema_name, table_name = \
+                    self.get_schema_and_table_name(row['partition_name'])
+
+                part_data['schema'] = schema_name
+                part_data['name'] = table_name
+            else:
+                part_data['schema'] = partitions['schema']
+                part_data['relispartition'] = True
+                part_data['name'] = row['partition_name']
+
+            if partitions['partition_type'] == 'range':
+                range_from = row['values_from'].split(',')
+                range_to = row['values_to'].split(',')
+
+                from_str = ', '.join("{0}".format(item) for item in range_from)
+                to_str = ', '.join("{0}".format(item) for item in range_to)
+
+                part_data['partition_value'] = 'FOR VALUES FROM (' + from_str \
+                                               + ') TO (' + to_str + ')'
+            else:
+                range_in = row['values_in'].split(',')
+                in_str = ', '.join("{0}".format(item) for item in range_in)
+                part_data['partition_value'] = 'FOR VALUES IN (' + in_str + ')'
+
+            if 'is_attach' in row and row['is_attach']:
+                partition_sql = render_template(
+                    "/".join([self.partition_template_path, 'attach.sql']),
+                    data=part_data, conn=self.conn
+                )
+            else:
+                partition_sql = render_template(
+                    "/".join([self.partition_template_path, 'create.sql']),
+                    data=part_data, conn=self.conn
+                )
+
+            sql += partition_sql + '\n'
+
+        return sql
+
+    def truncate(self, gid, sid, did, scid, tid, res):
+        """
+        This function will truncate the table object
+
+         Args:
+           gid: Server Group ID
+           sid: Server ID
+           did: Database ID
+           scid: Schema ID
+           tid: Table ID
+        """
+        # Below will decide if it's simple drop or drop with cascade call
+        data = request.form if request.form else json.loads(
+            request.data, encoding='utf-8'
+        )
+        # Convert str 'true' to boolean type
+        is_cascade = json.loads(data['cascade'])
+
+        data = res['rows'][0]
+
+        SQL = render_template("/".join([self.table_template_path,
+                                        'truncate.sql']),
+                              data=data, cascade=is_cascade)
+        status, res = self.conn.execute_scalar(SQL)
+        if not status:
+            return internal_server_error(errormsg=res)
+
+        return make_json_response(
+            success=1,
+            info=gettext("Table truncated"),
+            data={
+                'id': tid,
+                'scid': scid
+            }
+        )
+
+    def get_schema_and_table_name(self, tid):
+        """
+        This function will fetch the schema qualified name of the
+        given table id.
+
+        :param tid: Table Id.
+        """
+        # Get schema oid
+        status, scid = self.conn.execute_scalar(
+            render_template("/".join([self.table_template_path,
+                                      'get_schema_oid.sql']), tid=tid))
+        if not status:
+            return internal_server_error(errormsg=scid)
+
+        # Fetch schema name
+        status, schema_name = self.conn.execute_scalar(
+            render_template("/".join([self.table_template_path,
+                                      'get_schema.sql']), conn=self.conn,
+                            scid=scid)
+        )
+        if not status:
+            return internal_server_error(errormsg=schema_name)
+
+        # Fetch Table name
+        status, table_name = self.conn.execute_scalar(
+            render_template(
+                "/".join([self.table_template_path, 'get_table.sql']),
+                conn=self.conn, scid=scid, tid=tid
+            )
+        )
+        if not status:
+            return internal_server_error(errormsg=table_name)
+
+        return schema_name, table_name
+
+    @staticmethod
+    def convert_length_precision_to_string(data):
+        """
+        This function is used to convert length & precision to string
+        to handle case like when user gives 0 as length
+
+        Args:
+            data: Data from client
+
+        Returns:
+            Converted data
+        """
+        if 'attlen' in data and data['attlen'] is not None:
+            data['attlen'] = str(data['attlen'])
+        if 'attprecision' in data and data['attprecision'] is not None:
+            data['attprecision'] = str(data['attprecision'])
+        return data
+
+    def search_coveringindex(self, tid, cols):
+        """
+
+        Args:
+          tid: Table id
+          cols: column list
+
+        Returns:
+
+        """
+
+        cols = set(cols)
+        SQL = render_template("/".join([self.foreign_key_template_path,
+                                        'get_constraints.sql']),
+                              tid=tid)
+        status, constraints = self.conn.execute_dict(SQL)
+
+        if not status:
+            raise Exception(constraints)
+
+        for costrnt in constraints['rows']:
+
+            sql = render_template(
+                "/".join([self.foreign_key_template_path, 'get_cols.sql']),
+                cid=costrnt['oid'],
+                colcnt=costrnt['indnatts'])
+            status, rest = self.conn.execute_dict(sql)
+
+            if not status:
+                return internal_server_error(errormsg=rest)
+
+            indexcols = set()
+            for r in rest['rows']:
+                indexcols.add(r['column'].strip('"'))
+
+            if len(cols - indexcols) == len(indexcols - cols) == 0:
+                return costrnt["idxname"]
+
+        return None
\ No newline at end of file
diff --git a/web/pgadmin/tools/backup/templates/backup/js/backup.js b/web/pgadmin/tools/backup/templates/backup/js/backup.js
index c43dcd2..3b58455 100644
--- a/web/pgadmin/tools/backup/templates/backup/js/backup.js
+++ b/web/pgadmin/tools/backup/templates/backup/js/backup.js
@@ -270,7 +270,7 @@ TODO LIST FOR BACKUP:
 
         // Define list of nodes on which backup context menu option appears
         var backup_supported_nodes = [
-              'database', 'schema', 'table'
+              'database', 'schema', 'table', 'partition'
             ];
 
         /**
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index 67f6729..839b244 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -127,6 +127,10 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
         return internal_server_error(errormsg=str(msg))
 
     try:
+        # if object type is partition then it is nothing but a table.
+        if obj_type == 'partition':
+            obj_type = 'table'
+
         # Get the object as per the object type
         command_obj = ObjectRegistry.get_object(obj_type, conn_id=conn_id, sid=sid,
                                                 did=did, obj_id=obj_id, cmd_type=cmd_type,
diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/js/datagrid.js b/web/pgadmin/tools/datagrid/templates/datagrid/js/datagrid.js
index eb86a12..cda5c53 100644
--- a/web/pgadmin/tools/datagrid/templates/datagrid/js/datagrid.js
+++ b/web/pgadmin/tools/datagrid/templates/datagrid/js/datagrid.js
@@ -29,7 +29,7 @@ define([
         // Define list of nodes on which view data option appears
         var supported_nodes = [
            'table', 'view', 'mview',
-           'foreign-table', 'catalog_object'
+           'foreign-table', 'catalog_object', 'partition'
         ],
 
         /* Enable/disable View data menu in tools based
diff --git a/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js b/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js
index 5ab3c44..0e51fd9 100644
--- a/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js
+++ b/web/pgadmin/tools/maintenance/templates/maintenance/js/maintenance.js
@@ -150,7 +150,7 @@ define([
 
         var maintenance_supported_nodes = [
               'database', 'table', 'primary_key',
-              'unique_constraint', 'index'
+              'unique_constraint', 'index', 'partition'
             ];
 
         /**
@@ -180,7 +180,7 @@ define([
 
         var menus = [{
           name: 'maintenance', module: this,
-          applies: ['tools'], callback: 'callback_maintenace',
+          applies: ['tools'], callback: 'callback_maintenance',
           priority: 10, label: gettext('Maintenance...'),
           icon: 'fa fa-wrench', enable: menu_enabled
         }];
@@ -190,7 +190,7 @@ define([
           menus.push({
             name: 'maintenance_context_' + maintenance_supported_nodes[idx],
             node: maintenance_supported_nodes[idx], module: this,
-            applies: ['context'], callback: 'callback_maintenace',
+            applies: ['context'], callback: 'callback_maintenance',
             priority: 10, label: gettext('Maintenance...'),
             icon: 'fa fa-wrench', enable: menu_enabled
           });
@@ -201,7 +201,7 @@ define([
       /*
         Open the dialog for the maintenance functionality
       */
-      callback_maintenace: function(args, item) {
+      callback_maintenance: function(args, item) {
         var i = item || pgBrowser.tree.selected(),
           server_data = null;
 
@@ -320,7 +320,10 @@ define([
                   if (treeInfo.schema != undefined) {
                     schema = treeInfo.schema._label;
                   }
-                  if (treeInfo.table != undefined) {
+
+                  if (treeInfo.partition != undefined) {
+                    table = treeInfo.partition._label;
+                  } else if  (treeInfo.table != undefined) {
                     table = treeInfo.table._label;
                   }
 
diff --git a/web/pgadmin/tools/restore/templates/restore/js/restore.js b/web/pgadmin/tools/restore/templates/restore/js/restore.js
index c23d9e3..0da0004 100644
--- a/web/pgadmin/tools/restore/templates/restore/js/restore.js
+++ b/web/pgadmin/tools/restore/templates/restore/js/restore.js
@@ -228,7 +228,8 @@ define([
         var restore_supported_nodes = [
               'database', 'schema',
               'table', 'function',
-              'trigger', 'index'
+              'trigger', 'index',
+              'partition'
             ];
 
         /**
diff --git a/web/pgadmin/utils/__init__.py b/web/pgadmin/utils/__init__.py
index 550bad2..701a38c 100644
--- a/web/pgadmin/utils/__init__.py
+++ b/web/pgadmin/utils/__init__.py
@@ -29,6 +29,7 @@ class PgAdminModule(Blueprint):
         kwargs.setdefault('template_folder', 'templates')
         kwargs.setdefault('static_folder', 'static')
         self.submodules = []
+        self.parentmodules = []
 
         super(PgAdminModule, self).__init__(name, import_name, **kwargs)
 
@@ -59,6 +60,8 @@ class PgAdminModule(Blueprint):
         super(PgAdminModule, self).register(app, options, first_registration)
 
         for module in self.submodules:
+            if first_registration:
+                module.parentmodules.append(self)
             app.register_blueprint(module)
 
     def get_own_stylesheets(self):
diff --git a/web/pgadmin/utils/exception.py b/web/pgadmin/utils/exception.py
index 57c3224..77d59da 100644
--- a/web/pgadmin/utils/exception.py
+++ b/web/pgadmin/utils/exception.py
@@ -40,3 +40,11 @@ class ConnectionLost(HTTPException):
                 'conn_id': self.conn_id
             }
         )
+
+    def __str__(self):
+        return "Connection (id #{2}) lost for the server (#{0}) on " \
+               "database ({1})".format(self.sid, self.db, self.conn_id)
+
+    def __repr__(self):
+        return "Connection (id #{2}) lost for the server (#{0}) on " \
+               "database ({1})".format(self.sid, self.db, self.conn_id)


view thread (77+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: [pgadmin-hackers] Declarative partitioning in pgAdmin4
  In-Reply-To: <CANxoLDeZ6YO5_yXX9A12uafA9BS32nMKY-LwUSqxWKhSr21gig@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox