Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

%sqlcmd profile does not work with postgres "quoted" fields and throw: column does not exist error #1023

Open
Hubbitus opened this issue Aug 31, 2024 · 0 comments

Comments

@Hubbitus
Copy link

Hubbitus commented Aug 31, 2024

What happens?

Postgres has so called quoted identifier where case of table name and fields became significant.

%sqlcmd profile throw "column X does not exist error" on such tables.

To Reproduce

from sqlalchemy import create_engine
from ipython_secrets import *

try:
    db_url = f'postgresql://data:{get_secret("DB_PASSWORD_PG")}@10.1.1.1:10266/apidev'
    engine = create_engine(db_url)

    %sql engine --alias PG
finally:
    db_url = None

%sqlcmd profile --table "group"
---------------------------------------------------------------------------
UndefinedColumn                           Traceback (most recent call last)
File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1965, in Connection._exec_single_context(self, dialect, context, statement, parameters)
   1964     if not evt_handled:
-> 1965         self.dialect.do_execute(
   1966             cursor, str_statement, effective_parameters, context
   1967         )
   1969 if self._has_events or self.engine._has_events:

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/default.py:921, in DefaultDialect.do_execute(self, cursor, statement, parameters, context)
    920 def do_execute(self, cursor, statement, parameters, context=None):
--> 921     cursor.execute(statement, parameters)

UndefinedColumn: column "createdat" does not exist
LINE 1: SELECT createdAt FROM "group" LIMIT 1
               ^
HINT:  Perhaps you meant to reference the column "group.createdAt".


The above exception was the direct cause of the following exception:

ProgrammingError                          Traceback (most recent call last)
Cell In[14], line 1
----> 1 get_ipython().run_line_magic('sqlcmd', 'profile --table "group"')
      3 # UndefinedColumn: column "createdat" does not exist
      4 # LINE 1: SELECT createdAt FROM "group" LIMIT 1
      5 # TODO fill BUG

File /opt/conda/lib/python3.11/site-packages/IPython/core/interactiveshell.py:2417, in InteractiveShell.run_line_magic(self, magic_name, line, _stack_depth)
   2415     kwargs['local_ns'] = self.get_local_scope(stack_depth)
   2416 with self.builtin_trap:
-> 2417     result = fn(*args, **kwargs)
   2419 # The code below prevents the output from being displayed
   2420 # when using magics with decodator @output_can_be_silenced
   2421 # when the last Python token in the expression is a ';'.
   2422 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):

File /opt/conda/lib/python3.11/site-packages/sql/magic_cmd.py:105, in SqlCmdMagic._validate_execute_inputs(self, line)
    102     if command in COMMANDS_SQLALCHEMY_ONLY:
    103         support_only_sql_alchemy_connection(f"%sqlcmd {command}")
--> 105     return self.execute(command, others)
    106 else:
    107     raise exceptions.UsageError(
    108         f"%sqlcmd has no command: {command!r}. "
    109         "Valid commands are: {}".format(
    110             ", ".join(AVAILABLE_SQLCMD_COMMANDS)
    111         )
    112     )

File /opt/conda/lib/python3.11/site-packages/sql/magic_cmd.py:135, in SqlCmdMagic.execute(self, cmd_name, others, cell, local_ns)
    133     return cmd(others)
    134 else:
--> 135     return cmd(others, self.shell.user_ns.copy())

File /opt/conda/lib/python3.11/site-packages/sql/cmd/profile.py:42, in profile(others, user_ns)
     39 if is_rendering_required(" ".join(others)):
     40     expand_args(args, user_ns)
---> 42 report = inspect.get_table_statistics(schema=args.schema, name=args.table)
     44 if args.output:
     45     with open(args.output, "w") as f:

File /opt/conda/lib/python3.11/site-packages/ploomber_core/telemetry/telemetry.py:700, in Telemetry.log_call.<locals>._log_call.<locals>.wrapper(*args, **kwargs)
    698             result = func(_payload, *args, **kwargs)
    699     else:
--> 700         result = func(*args, **kwargs)
    701 except Exception as e:
    702     metadata_error = {
    703         # can we log None to posthog?
    704         "type": getattr(e, "type_", None),
   (...)
    707         **_payload,
    708     }

File /opt/conda/lib/python3.11/site-packages/sql/inspect.py:500, in get_table_statistics(name, schema)
    492 @telemetry.log_call()
    493 def get_table_statistics(name, schema=None):
    494     """Get table statistics for a given connection.
    495 
    496     For all data types the results will include `count`, `mean`, `std`, `min`
    497     `max`, `25`, `50` and `75` percentiles. It will also include `unique`, `top`
    498     and `freq` statistics.
    499     """
--> 500     return TableDescription(name, schema=schema)

File /opt/conda/lib/python3.11/site-packages/ploomber_core/exceptions.py:128, in modify_exceptions.<locals>.wrapper(*args, **kwargs)
    125 @wraps(fn)
    126 def wrapper(*args, **kwargs):
    127     try:
--> 128         return fn(*args, **kwargs)
    129     except (ValueError, TypeError) as e:
    130         _add_community_link(e)

File /opt/conda/lib/python3.11/site-packages/sql/inspect.py:259, in TableDescription.__init__(self, table_name, schema)
    257 # check the datatype of a column
    258 try:
--> 259     result = ConnectionManager.current.raw_execute(
    260         f"""SELECT {column} FROM {table_name} LIMIT 1"""
    261     ).fetchone()
    263     value = result[0]
    264     is_numeric = isinstance(value, (int, float)) or (
    265         isinstance(value, str) and _is_numeric(value)
    266     )

File /opt/conda/lib/python3.11/site-packages/sql/connection/connection.py:824, in SQLAlchemyConnection.raw_execute(self, query, parameters, with_)
    822 else:
    823     try:
--> 824         return self._connection_execute(query, parameters)
    825     except StatementError as e:
    826         # add a more helpful message if the users passes :variable but
    827         # the feature isn't enabled
    828         if parameters is None:

File /opt/conda/lib/python3.11/site-packages/sql/connection/connection.py:731, in SQLAlchemyConnection._connection_execute(self, query, parameters)
    728     raise NotImplementedError("Only one statement is supported.")
    730 operation = partial(self._execute_with_parameters, query, parameters)
--> 731 out = self._execute_with_error_handling(operation)
    733 if self._requires_manual_commit:
    734     # Calling connection.commit() when using duckdb-engine will yield
    735     # empty results if we commit after a SELECT or SUMMARIZE statement,
    736     # see: https://github.com/Mause/duckdb_engine/issues/734.
    737     if self.dialect == "duckdb":

File /opt/conda/lib/python3.11/site-packages/sql/connection/connection.py:862, in SQLAlchemyConnection._execute_with_error_handling(self, operation)
    859 rollback_needed = False
    861 try:
--> 862     out = operation()
    864 # this is a generic error but we've seen it in postgres. it helps recover
    865 # from a idle session timeout (happens in psycopg 2 and psycopg 3)
    866 except PendingRollbackError:

File /opt/conda/lib/python3.11/site-packages/sql/connection/connection.py:767, in SQLAlchemyConnection._execute_with_parameters(self, query, parameters)
    765     out = self._connection.execute(sqlalchemy.text(query), **parameters)
    766 else:
--> 767     out = self._connection.execute(
    768         sqlalchemy.text(query), parameters=parameters
    769     )
    771 return out

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1412, in Connection.execute(self, statement, parameters, execution_options)
   1410     raise exc.ObjectNotExecutableError(statement) from err
   1411 else:
-> 1412     return meth(
   1413         self,
   1414         distilled_parameters,
   1415         execution_options or NO_OPTIONS,
   1416     )

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/sql/elements.py:483, in ClauseElement._execute_on_connection(self, connection, distilled_params, execution_options)
    481     if TYPE_CHECKING:
    482         assert isinstance(self, Executable)
--> 483     return connection._execute_clauseelement(
    484         self, distilled_params, execution_options
    485     )
    486 else:
    487     raise exc.ObjectNotExecutableError(self)

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1635, in Connection._execute_clauseelement(self, elem, distilled_parameters, execution_options)
   1623 compiled_cache: Optional[CompiledCacheType] = execution_options.get(
   1624     "compiled_cache", self.engine._compiled_cache
   1625 )
   1627 compiled_sql, extracted_params, cache_hit = elem._compile_w_cache(
   1628     dialect=dialect,
   1629     compiled_cache=compiled_cache,
   (...)
   1633     linting=self.dialect.compiler_linting | compiler.WARN_LINTING,
   1634 )
-> 1635 ret = self._execute_context(
   1636     dialect,
   1637     dialect.execution_ctx_cls._init_compiled,
   1638     compiled_sql,
   1639     distilled_parameters,
   1640     execution_options,
   1641     compiled_sql,
   1642     distilled_parameters,
   1643     elem,
   1644     extracted_params,
   1645     cache_hit=cache_hit,
   1646 )
   1647 if has_events:
   1648     self.dispatch.after_execute(
   1649         self,
   1650         elem,
   (...)
   1654         ret,
   1655     )

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1844, in Connection._execute_context(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)
   1839     return self._exec_insertmany_context(
   1840         dialect,
   1841         context,
   1842     )
   1843 else:
-> 1844     return self._exec_single_context(
   1845         dialect, context, statement, parameters
   1846     )

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1984, in Connection._exec_single_context(self, dialect, context, statement, parameters)
   1981     result = context._setup_result_proxy()
   1983 except BaseException as e:
-> 1984     self._handle_dbapi_exception(
   1985         e, str_statement, effective_parameters, cursor, context
   1986     )
   1988 return result

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:2339, in Connection._handle_dbapi_exception(self, e, statement, parameters, cursor, context, is_sub_exec)
   2337 elif should_wrap:
   2338     assert sqlalchemy_exception is not None
-> 2339     raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
   2340 else:
   2341     assert exc_info[1] is not None

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1965, in Connection._exec_single_context(self, dialect, context, statement, parameters)
   1963                 break
   1964     if not evt_handled:
-> 1965         self.dialect.do_execute(
   1966             cursor, str_statement, effective_parameters, context
   1967         )
   1969 if self._has_events or self.engine._has_events:
   1970     self.dispatch.after_cursor_execute(
   1971         self,
   1972         cursor,
   (...)
   1976         context.executemany,
   1977     )

File /opt/conda/lib/python3.11/site-packages/sqlalchemy/engine/default.py:921, in DefaultDialect.do_execute(self, cursor, statement, parameters, context)
    920 def do_execute(self, cursor, statement, parameters, context=None):
--> 921     cursor.execute(statement, parameters)

ProgrammingError: (psycopg2.errors.UndefinedColumn) column "createdat" does not exist
LINE 1: SELECT createdAt FROM "group" LIMIT 1
               ^
HINT:  Perhaps you meant to reference the column "group.createdAt".

[SQL: SELECT createdAt FROM "group" LIMIT 1]
(Background on this error at: https://sqlalche.me/e/20/f405)

OS:

Linux

JupySQL Version:

0.10.12

Full Name:

Pavel Alexeev

Affiliation:

GID

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant