From 634cd5381749d1be3c5f7f7a8ecafde0c56e9725 Mon Sep 17 00:00:00 2001
From: Joao Pereira and Sarah McAlear <pair+jpereira+smcalear@pivotal.io>
Date: Thu, 23 Mar 2017 11:19:08 -0400
Subject: [PATCH] Raise InternalServerError instead of returning
 internal_server_error in Table DDL retrieval

---
 .../servers/databases/schemas/tables/__init__.py   | 433 +++++++++++----------
 1 file changed, 219 insertions(+), 214 deletions(-)

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 5311db85..15106bd5 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
@@ -13,6 +13,8 @@ import simplejson as json
 import re
 from functools import wraps
 
+from werkzeug.exceptions import InternalServerError
+
 import pgadmin.browser.server_groups.servers.databases as database
 from flask import render_template, request, jsonify
 from flask_babel import gettext
@@ -783,7 +785,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         status, result = self.conn.execute_dict(sql)
 
         if not status:
-            return internal_server_error(errormsg=result)
+            raise InternalServerError(result)
 
         for fk in result['rows']:
 
@@ -814,7 +816,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
             status, rset = self.conn.execute_2darray(SQL)
             if not status:
-                return internal_server_error(errormsg=rset)
+                raise InternalServerError(rset)
 
             fk['remote_schema'] = rset['rows'][0]['schema']
             fk['remote_table'] = rset['rows'][0]['table']
@@ -853,7 +855,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
         status, res = self.conn.execute_dict(SQL)
 
         if not status:
-            return internal_server_error(errormsg=res)
+            raise InternalServerError(res)
         # If not exists then create list and/or append into
         # existing list [ Adding into main data dict]
 
@@ -983,7 +985,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                               tid=tid, scid=scid)
         status, acl = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=acl)
+            raise InternalServerError(acl)
 
         # We will set get privileges from acl sql so we don't need
         # it from properties sql
@@ -1014,7 +1016,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
             status, res = self.conn.execute_dict(SQL)
             if not status:
-                return internal_server_error(errormsg=res)
+                raise InternalServerError(res)
             data['columns'] = res['rows']
 
         # Get inherited table(s) columns and add it into columns dict
@@ -1027,7 +1029,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                                   )
             status, rset = self.conn.execute_2darray(SQL)
             if not status:
-                return internal_server_error(errormsg=rset)
+                raise InternalServerError(rset)
 
             for row in rset['rows']:
                 if row['inherits'] in data['coll_inherits']:
@@ -1037,7 +1039,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
                                           tid=row['oid'])
                     status, res = self.conn.execute_dict(SQL)
                     if not status:
-                        return internal_server_error(errormsg=res)
+                        raise InternalServerError(res)
                     columns.extend(res['rows'][:])
             data['columns'] = columns
 
@@ -1051,7 +1053,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
 
         status, res = self.conn.execute_dict(SQL)
         if not status:
-            return internal_server_error(errormsg=res)
+            raise InternalServerError(res)
         all_columns = res['rows']
 
         # Filter inherited columns from all columns
@@ -2444,261 +2446,264 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings):
            scid: Schema ID
            tid: Table ID
         """
-        main_sql = []
-
-        """
-        #####################################
-        # 1) Reverse engineered sql for TABLE
-        #####################################
-        """
-        SQL = render_template("/".join([self.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]
-
-        # 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)
+        try:
+            main_sql = []
 
-        # 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)
+            """
+            #####################################
+            # 1) Reverse engineered sql for TABLE
+            #####################################
+            """
+            SQL = render_template("/".join([self.template_path,
+                                            'properties.sql']),
+                                  did=did, scid=scid, tid=tid,
+                                  datlastsysoid=self.datlastsysoid)
+            status, res = self.conn.execute_dict(SQL)
+            if not status:
+                raise InternalServerError(res)
 
-                # check type for '[]' in it
-                if 'cltype' in c:
-                    c['cltype'], c['hasSqrBracket'] = self._cltype_formatter(c['cltype'])
+            data = res['rows'][0]
 
-        sql_header = u"-- Table: {0}\n\n-- ".format(self.qtIdent(self.conn,
-                                                                data['schema'],
-                                                                data['name']))
+            # Table & Schema declaration so that we can use them in child nodes
+            schema = data['schema']
+            table = data['name']
 
-        sql_header += render_template("/".join([self.template_path,
-                                                'delete.sql']),
-                                      data=data, conn=self.conn)
+            data = self._formatter(did, scid, tid, data)
 
-        sql_header = sql_header.strip('\n')
-        sql_header += '\n'
+            # 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)
 
-        # Add into main sql
-        main_sql.append(sql_header)
+                    # check type for '[]' in it
+                    if 'cltype' in c:
+                        c['cltype'], c['hasSqrBracket'] = self._cltype_formatter(c['cltype'])
 
-        # Parse privilege data
-        if 'relacl' in data:
-            data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
+            sql_header = u"-- Table: {0}\n\n-- ".format(self.qtIdent(self.conn,
+                                                                    data['schema'],
+                                                                    data['name']))
 
-        # 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)
+            sql_header += render_template("/".join([self.template_path,
+                                                    'delete.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'))
+            sql_header = sql_header.strip('\n')
+            sql_header += '\n'
 
-        """
-        ######################################
-        # 2) Reverse engineered sql for INDEX
-        ######################################
-        """
+            # Add into main sql
+            main_sql.append(sql_header)
 
-        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)
+            # Parse privilege data
+            if 'relacl' in data:
+                data['relacl'] = parse_priv_to_db(data['relacl'], self.acl)
 
-        for row in rset['rows']:
+            # 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)
 
-            SQL = render_template("/".join([self.index_template_path,
-                                            'properties.sql']),
-                                  did=did, tid=tid, idx=row['oid'],
-                                  datlastsysoid=self.datlastsysoid)
+            # Add into main sql
+            table_sql = re.sub('\n{2,}', '\n\n', table_sql)
+            main_sql.append(table_sql.strip('\n'))
 
-            status, res = self.conn.execute_dict(SQL)
-            if not status:
-                return internal_server_error(errormsg=res)
+            """
+            ######################################
+            # 2) Reverse engineered sql for INDEX
+            ######################################
+            """
 
-            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'])
+                                            'nodes.sql']), tid=tid)
             status, rset = self.conn.execute_2darray(SQL)
             if not status:
-                return internal_server_error(errormsg=rset)
+                raise InternalServerError(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 row in rset['rows']:
-                # We need all data as collection for ColumnsModel
-                cols_data = {
-                    'colname': row['attdef'].strip('"'),
-                    'collspcname': row['collnspname'],
-                    'op_class': row['opcname'],
-                }
-                if 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 = row['attdef']
-                if row['collnspname']:
-                    cols_str += ' COLLATE ' + row['collnspname']
-                if row['opcname']:
-                    cols_str += ' ' + row['opcname']
-                if 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)
+                SQL = render_template("/".join([self.index_template_path,
+                                                'properties.sql']),
+                                      did=did, tid=tid, idx=row['oid'],
+                                      datlastsysoid=self.datlastsysoid)
 
-            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 = ''
+                status, res = self.conn.execute_dict(SQL)
+                if not status:
+                    raise InternalServerError(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:
+                    raise InternalServerError(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 row in rset['rows']:
+                    # We need all data as collection for ColumnsModel
+                    cols_data = {
+                        'colname': row['attdef'].strip('"'),
+                        'collspcname': row['collnspname'],
+                        'op_class': row['opcname'],
+                    }
+                    if 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 = row['attdef']
+                    if row['collnspname']:
+                        cols_str += ' COLLATE ' + row['collnspname']
+                    if row['opcname']:
+                        cols_str += ' ' + row['opcname']
+                    if 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,
-                                            'properties.sql']),
-                                  tid=tid, trid=row['oid'],
-                                  datlastsysoid=self.datlastsysoid)
-
-            status, res = self.conn.execute_dict(SQL)
+                                            'nodes.sql']), tid=tid)
+            status, rset = self.conn.execute_2darray(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
+                raise InternalServerError(rset)
 
-            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(' '))
+            for row in rset['rows']:
+                trigger_sql = ''
 
                 SQL = render_template("/".join([self.trigger_template_path,
-                                                'get_columns.sql']),
-                                      tid=tid, clist=columns)
+                                                'properties.sql']),
+                                      tid=tid, trid=row['oid'],
+                                      datlastsysoid=self.datlastsysoid)
 
-                status, rset = self.conn.execute_2darray(SQL)
+                status, res = self.conn.execute_dict(SQL)
                 if not status:
-                    return internal_server_error(errormsg=rset)
-                # 'tgattr' contains list of columns from table used in trigger
-                columns = []
+                    raise InternalServerError(res)
 
-                for row in rset['rows']:
-                    columns.append({'column': row['name']})
+                data = dict(res['rows'][0])
+                # Adding parent into data dict, will be using it while creating sql
+                data['schema'] = schema
+                data['table'] = table
 
-                data['columns'] = columns
+                if data['tgnargs'] > 1:
+                    # We know that trigger has more than 1 arguments, let's join them
+                    data['tgargs'] = ', '.join(data['tgargs'])
 
-            data = trigger_definition(data)
+                if len(data['tgattr']) > 1:
+                    columns = ', '.join(data['tgattr'].split(' '))
 
-            sql_header = u"\n-- Trigger: {0}\n\n-- ".format(data['name'])
+                    SQL = render_template("/".join([self.trigger_template_path,
+                                                    'get_columns.sql']),
+                                          tid=tid, clist=columns)
 
-            sql_header += render_template("/".join([self.trigger_template_path,
-                                                    'delete.sql']),
-                                          data=data, conn=self.conn)
+                    status, rset = self.conn.execute_2darray(SQL)
+                    if not status:
+                        raise InternalServerError(rset)
+                    # 'tgattr' contains list of columns from table used in trigger
+                    columns = []
 
-            # 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)
+                    for row in rset['rows']:
+                        columns.append({'column': row['name']})
 
-            trigger_sql = sql_header + '\n\n' + trigger_sql.strip('\n')
+                    data['columns'] = columns
 
-            # 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)
+                data = trigger_definition(data)
 
-            # Add into main sql
-            trigger_sql = re.sub('\n{2,}', '\n\n', trigger_sql)
-            main_sql.append(trigger_sql)
+                sql_header = u"\n-- Trigger: {0}\n\n-- ".format(data['name'])
 
-        """
-        #####################################
-        # 4) Reverse engineered sql for RULES
-        #####################################
-        """
+                sql_header += render_template("/".join([self.trigger_template_path,
+                                                        'delete.sql']),
+                                              data=data, conn=self.conn)
 
-        SQL = render_template("/".join(
-            [self.rules_template_path, 'properties.sql']), tid=tid)
+                # 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)
 
-        status, rset = self.conn.execute_2darray(SQL)
-        if not status:
-            return internal_server_error(errormsg=rset)
+                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
+            #####################################
+            """
 
-        for row in rset['rows']:
-            rules_sql = '\n'
             SQL = render_template("/".join(
-                [self.rules_template_path, 'properties.sql']
-            ), rid=row['oid'], datlastsysoid=self.datlastsysoid)
+                [self.rules_template_path, 'properties.sql']), tid=tid)
 
-            status, res = self.conn.execute_dict(SQL)
+            status, rset = self.conn.execute_2darray(SQL)
             if not status:
-                return internal_server_error(errormsg=res)
+                raise InternalServerError(rset)
 
-            res_data = parse_rule_definition(res)
-            rules_sql += render_template("/".join(
-                [self.rules_template_path, 'create.sql']),
-                data=res_data, display_comments=True)
+            for row in rset['rows']:
+                rules_sql = '\n'
+                SQL = render_template("/".join(
+                    [self.rules_template_path, 'properties.sql']
+                ), rid=row['oid'], datlastsysoid=self.datlastsysoid)
 
-            # Add into main sql
-            rules_sql = re.sub('\n{2,}', '\n\n', rules_sql)
-            main_sql.append(rules_sql)
+                status, res = self.conn.execute_dict(SQL)
+                if not status:
+                    raise InternalServerError(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)
 
-        sql = '\n'.join(main_sql)
+            sql = '\n'.join(main_sql)
+        except InternalServerError as e:
+            return internal_server_error(e.description)
 
         return ajax_response(response=sql.strip('\n'))
 
-- 
2.12.0

