1515from pandas import DataFrame
1616from sqlalchemy import inspect
1717from sqlalchemy .engine .reflection import Inspector
18+ from sqlalchemy .exc import NoSuchTableError
1819
1920from noteable_magics .sql .connection import Connection
2021from noteable_magics .sql .gate_messaging_types import (
@@ -399,21 +400,17 @@ def run(self, invoked_as: str, args: List[str]) -> Tuple[DataFrame, bool]:
399400
400401 inspector = self .get_inspector ()
401402
402- is_view = relation_name in inspector .get_view_names (schema )
403-
404- if not is_view :
405- # Ensure is a table
406- if relation_name not in inspector .get_table_names (schema ):
407- if schema :
408- msg = f'Relation { schema } .{ relation_name } does not exist'
409- else :
410- msg = f'Relation { relation_name } does not exist'
411- raise MetaCommandException (msg )
412- rtype = 'Table'
413- else :
414- rtype = 'View'
403+ try :
404+ # In some dialects (BigQuery), this will raise NoSuchTableError if
405+ # the table doesn't exist. Yay, sane.
415406
416- column_dicts = inspector .get_columns (relation_name , schema = schema )
407+ # On some dialects (sigh, CockroachDB, what are you doing??),
408+ # this call may succeed returning empty list even if
409+ # the named relation does not exist. But the call to get_pk_constraint()
410+ # down below will then raise NoSuchTableError.
411+ column_dicts = inspector .get_columns (relation_name , schema = schema )
412+ except NoSuchTableError :
413+ self ._raise_from_no_such_table (schema , relation_name )
417414
418415 # 'Pivot' the dicts from get_columns()
419416 names = []
@@ -454,11 +451,19 @@ def run(self, invoked_as: str, args: List[str]) -> Tuple[DataFrame, bool]:
454451
455452 displayable_rname = displayable_relation_name (schema , relation_name )
456453
454+ if is_view := relation_name in inspector .get_view_names (schema ):
455+ rtype = 'View'
456+ else :
457+ rtype = 'Table'
458+
457459 main_relation_df = set_dataframe_metadata (
458460 DataFrame (data = data ), title = f'{ rtype } "{ displayable_rname } " Structure'
459461 )
460462
461- display (main_relation_df )
463+ # Keep a list of things to call display() on. Only do so at the very
464+ # end if we don't hit any exceptions.
465+
466+ displayables = [main_relation_df ]
462467
463468 if is_view :
464469 view_definition = inspector .get_view_definition (relation_name , schema )
@@ -472,7 +477,7 @@ def run(self, invoked_as: str, args: List[str]) -> Tuple[DataFrame, bool]:
472477 html_buf .append ('<br />' )
473478 html_buf .append (f'<pre>{ view_definition } </pre>' )
474479
475- display (HTML ('\n ' .join (html_buf )))
480+ displayables . append (HTML ('\n ' .join (html_buf )))
476481 else :
477482 # Is a table. Let's go get indices, foreign keys, other table constraints.
478483 # If meaningful dataframe returned for any of these, transform to
@@ -484,7 +489,11 @@ def run(self, invoked_as: str, args: List[str]) -> Tuple[DataFrame, bool]:
484489 ):
485490 secondary_df = secondary_function (inspector , relation_name , schema )
486491 if len (secondary_df ):
487- display (secondary_dataframe_to_html (secondary_df ))
492+ displayables .append (secondary_dataframe_to_html (secondary_df ))
493+
494+ # Make it this far? Display what we should display.
495+ for displayable in displayables :
496+ display (displayable )
488497
489498 return main_relation_df , False
490499
@@ -598,7 +607,7 @@ def all_table_and_views(self, inspector) -> List[Tuple[str, str, str]]:
598607 default_schema = inspector .default_schema_name
599608 all_schemas = set (inspector .get_schema_names ())
600609 all_schemas .difference_update (self .AVOID_SCHEMAS )
601- if default_schema not in all_schemas :
610+ if default_schema and default_schema not in all_schemas :
602611 all_schemas .add (default_schema )
603612
604613 for schema_name in sorted (all_schemas ):
@@ -971,7 +980,10 @@ def index_dataframe(
971980 uniques : List [bool ] = []
972981
973982 # Primary key index is ... treated special by SQLA for some reason. Sigh.
974- primary_index_dict = inspector .get_pk_constraint (table_name , schema )
983+ try :
984+ primary_index_dict = inspector .get_pk_constraint (table_name , schema )
985+ except NoSuchTableError :
986+ _raise_from_no_such_table (schema , table_name )
975987
976988 # If it returned something truthy with nonempty constrained_columns, then
977989 # we assume it described a real primary key constraint here.
@@ -1164,7 +1176,8 @@ def __init__(self, underlying_inspector: Inspector):
11641176
11651177 # Direct passthrough attributes / methods
11661178 @property
1167- def default_schema_name (self ) -> str :
1179+ def default_schema_name (self ) -> Optional [str ]:
1180+ # BigQuery, Trino dialects may end up returning None.
11681181 return self .underlying_inspector .default_schema_name
11691182
11701183 def get_schema_names (self ) -> List [str ]:
@@ -1183,16 +1196,19 @@ def get_foreign_keys(self, table_name: str, schema: Optional[str] = None) -> Lis
11831196 return self .underlying_inspector .get_foreign_keys (table_name , schema = schema )
11841197
11851198 def get_check_constraints (self , table_name : str , schema : Optional [str ] = None ) -> List [dict ]:
1186- return self .underlying_inspector .get_check_constraints (table_name , schema = schema )
1199+ try :
1200+ return self .underlying_inspector .get_check_constraints (table_name , schema = schema )
1201+ except NotImplementedError :
1202+ return []
11871203
11881204 def get_indexes (self , table_name : str , schema : Optional [str ] = None ) -> List [dict ]:
11891205 return self .underlying_inspector .get_indexes (table_name , schema = schema )
11901206
11911207 def get_unique_constraints (self , table_name : str , schema : Optional [str ] = None ) -> List [dict ]:
1192- return self . underlying_inspector . get_unique_constraints ( table_name , schema = schema )
1193-
1194- def get_check_constraints ( self , table_name : str , schema : Optional [ str ] = None ) -> List [ dict ] :
1195- return self . underlying_inspector . get_check_constraints ( table_name , schema = schema )
1208+ try :
1209+ return self . underlying_inspector . get_unique_constraints ( table_name , schema = schema )
1210+ except NotImplementedError :
1211+ return []
11961212
11971213 # Now the value-adding filtering methods.
11981214 def get_table_names (self , schema : Optional [str ] = None ) -> List [str ]:
@@ -1211,3 +1227,12 @@ def _strip_schema(self, names: List[str], schema: Optional[str] = None) -> List[
12111227 # Remove "schema." from the start of each name if starts with.
12121228 # (name[False:] is equiv to name[0:], 'cause python bools are subclasses of ints)
12131229 return [name [name .startswith (prefix ) and len (prefix ) :] for name in names ]
1230+
1231+
1232+ def _raise_from_no_such_table (schema : str , relation_name : str ):
1233+ """Raise a MetaCommandException when eaten a NoSuchTableException"""
1234+ if schema :
1235+ msg = f'Relation { schema } .{ relation_name } does not exist'
1236+ else :
1237+ msg = f'Relation { relation_name } does not exist'
1238+ raise MetaCommandException (msg )
0 commit comments