Skip to content

Commit 395609d

Browse files
committed
Revert "SNOW-2267482 replacing SnowAPI calls with SQL calls (#3942)"
This reverts commit 1dec439.
1 parent e86dea3 commit 395609d

File tree

3 files changed

+74
-173
lines changed

3 files changed

+74
-173
lines changed

src/snowflake/snowpark/catalog.py

Lines changed: 63 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,15 @@
22
# Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
33
#
44

5-
from ctypes import ArgumentError
65
import re
7-
from typing import List, Optional, Union, TYPE_CHECKING
8-
9-
from snowflake.snowpark._internal.analyzer.analyzer_utils import unquote_if_quoted
10-
from snowflake.snowpark.exceptions import SnowparkSQLException, NotFoundError
6+
from typing import List, Optional, Union
117

128
try:
9+
from snowflake.core import Root # type: ignore
1310
from snowflake.core.database import Database # type: ignore
14-
from snowflake.core.database._generated.models import Database as ModelDatabase # type: ignore
11+
from snowflake.core.exceptions import NotFoundError
1512
from snowflake.core.procedure import Procedure
1613
from snowflake.core.schema import Schema # type: ignore
17-
from snowflake.core.schema._generated.models import Schema as ModelSchema # type: ignore
1814
from snowflake.core.table import Table, TableColumn
1915
from snowflake.core.user_defined_function import UserDefinedFunction
2016
from snowflake.core.view import View
@@ -23,30 +19,27 @@
2319
"Missing optional dependency: 'snowflake.core'."
2420
) from e # pragma: no cover
2521

26-
from snowflake.snowpark._internal.type_utils import (
27-
convert_sp_to_sf_type,
28-
type_string_to_type_object,
29-
)
22+
23+
import snowflake.snowpark
24+
from snowflake.snowpark._internal.type_utils import convert_sp_to_sf_type
3025
from snowflake.snowpark.functions import lit, parse_json
3126
from snowflake.snowpark.types import DataType
3227

33-
if TYPE_CHECKING:
34-
from snowflake.snowpark.session import Session
35-
3628

3729
class Catalog:
3830
"""The Catalog class provides methods to interact with and manage the Snowflake objects.
3931
It allows users to list, get, and drop various database objects such as databases, schemas, tables,
4032
views, functions, etc.
4133
"""
4234

43-
def __init__(self, session: "Session") -> None:
35+
def __init__(self, session: "snowflake.snowpark.session.Session") -> None: # type: ignore
4436
self._session = session
37+
self._root = Root(session)
4538
self._python_regex_udf = None
4639

4740
def _parse_database(
4841
self,
49-
database: object,
42+
database: Optional[Union[str, Database]],
5043
model_obj: Optional[
5144
Union[str, Schema, Table, View, Procedure, UserDefinedFunction]
5245
] = None,
@@ -73,7 +66,7 @@ def _parse_database(
7366

7467
def _parse_schema(
7568
self,
76-
schema: object,
69+
schema: Optional[Union[str, Schema]],
7770
model_obj: Optional[
7871
Union[str, Table, View, Procedure, UserDefinedFunction]
7972
] = None,
@@ -173,28 +166,11 @@ def list_databases(
173166
pattern: the python regex pattern of name to match. Defaults to None.
174167
like: the sql style pattern for name to match. Default to None.
175168
"""
176-
like_str = f"LIKE '{like}'" if like else ""
177-
df = self._session.sql(f"SHOW AS RESOURCE DATABASES {like_str}")
169+
iter = self._root.databases.iter(like=like)
178170
if pattern:
179-
# initialize udf
180-
self._initialize_regex_udf()
181-
assert self._python_regex_udf is not None # pyright
182-
183-
# The result of SHOW AS RESOURCE query is a json string which contains
184-
# key 'name' to store the name of the object. We parse json for the returned
185-
# result and apply the filter on name.
186-
df = df.filter(
187-
self._python_regex_udf(
188-
lit(pattern), parse_json('"As Resource"')["name"]
189-
)
190-
)
171+
iter = filter(lambda x: re.match(pattern, x.name), iter)
191172

192-
return list(
193-
map(
194-
lambda row: Database._from_model(ModelDatabase.from_json(str(row[0]))),
195-
df.collect(),
196-
)
197-
)
173+
return list(iter)
198174

199175
def list_schemas(
200176
self,
@@ -212,28 +188,10 @@ def list_schemas(
212188
like: the sql style pattern for name to match. Default to None.
213189
"""
214190
db_name = self._parse_database(database)
215-
like_str = f"LIKE '{like}'" if like else ""
216-
df = self._session.sql(f"SHOW AS RESOURCE SCHEMAS {like_str} IN {db_name}")
191+
iter = self._root.databases[db_name].schemas.iter(like=like)
217192
if pattern:
218-
# initialize udf
219-
self._initialize_regex_udf()
220-
assert self._python_regex_udf is not None # pyright
221-
222-
# The result of SHOW AS RESOURCE query is a json string which contains
223-
# key 'name' to store the name of the object. We parse json for the returned
224-
# result and apply the filter on name.
225-
df = df.filter(
226-
self._python_regex_udf(
227-
lit(pattern), parse_json('"As Resource"')["name"]
228-
)
229-
)
230-
231-
return list(
232-
map(
233-
lambda row: Schema._from_model(ModelSchema.from_json(str(row[0]))),
234-
df.collect(),
235-
)
236-
)
193+
iter = filter(lambda x: re.match(pattern, x.name), iter)
194+
return list(iter)
237195

238196
def list_tables(
239197
self,
@@ -371,27 +329,14 @@ def get_current_schema(self) -> Optional[str]:
371329

372330
def get_database(self, database: str) -> Database:
373331
"""Name of the database to get"""
374-
try:
375-
return self.list_databases(like=unquote_if_quoted(database))[0]
376-
except IndexError:
377-
raise NotFoundError(f"Database with name {database} could not be found")
332+
return self._root.databases[database].fetch()
378333

379334
def get_schema(
380335
self, schema: str, *, database: Optional[Union[str, Database]] = None
381336
) -> Schema:
382337
"""Name of the schema to get."""
383338
db_name = self._parse_database(database)
384-
try:
385-
return self.list_schemas(database=db_name, like=unquote_if_quoted(schema))[
386-
0
387-
]
388-
except (
389-
IndexError, # schema with this name doesn't exist
390-
SnowparkSQLException, # database in which we are looking doesn't exist
391-
):
392-
raise NotFoundError(
393-
f"Schema with name {schema} could not be found in database '{db_name}'"
394-
)
339+
return self._root.databases[db_name].schemas[schema].fetch()
395340

396341
def get_table(
397342
self,
@@ -410,16 +355,12 @@ def get_table(
410355
"""
411356
db_name = self._parse_database(database)
412357
schema_name = self._parse_schema(schema)
413-
try:
414-
return self.listTables(
415-
database=db_name,
416-
schema=schema_name,
417-
like=unquote_if_quoted(table_name),
418-
)[0]
419-
except IndexError:
420-
raise NotFoundError(
421-
f"Table with name {table_name} could not be found in schema '{db_name}.{schema_name}'"
422-
)
358+
return (
359+
self._root.databases[db_name]
360+
.schemas[schema_name]
361+
.tables[table_name]
362+
.fetch()
363+
)
423364

424365
def get_view(
425366
self,
@@ -438,16 +379,9 @@ def get_view(
438379
"""
439380
db_name = self._parse_database(database)
440381
schema_name = self._parse_schema(schema)
441-
try:
442-
return self.list_views(
443-
database=db_name,
444-
schema=schema_name,
445-
like=unquote_if_quoted(view_name),
446-
)[0]
447-
except IndexError:
448-
raise NotFoundError(
449-
f"View with name {view_name} could not be found in schema '{db_name}.{schema_name}'"
450-
)
382+
return (
383+
self._root.databases[db_name].schemas[schema_name].views[view_name].fetch()
384+
)
451385

452386
def get_procedure(
453387
self,
@@ -469,19 +403,12 @@ def get_procedure(
469403
db_name = self._parse_database(database)
470404
schema_name = self._parse_schema(schema)
471405
procedure_id = self._parse_function_or_procedure(procedure_name, arg_types)
472-
473-
try:
474-
procedures = self._session.sql(
475-
f"DESCRIBE AS RESOURCE PROCEDURE {db_name}.{schema_name}.{procedure_id}"
476-
).collect()
477-
return Procedure.from_json(str(procedures[0][0]))
478-
except (
479-
IndexError, # when sql returned no results
480-
SnowparkSQLException, # when database, or schema doesn't exist
481-
):
482-
raise NotFoundError(
483-
f"Procedure with name {procedure_name} and arguments {arg_types} could not be found in schema '{db_name}.{schema_name}'"
484-
)
406+
return (
407+
self._root.databases[db_name]
408+
.schemas[schema_name]
409+
.procedures[procedure_id]
410+
.fetch()
411+
)
485412

486413
def get_user_defined_function(
487414
self,
@@ -504,19 +431,12 @@ def get_user_defined_function(
504431
db_name = self._parse_database(database)
505432
schema_name = self._parse_schema(schema)
506433
function_id = self._parse_function_or_procedure(udf_name, arg_types)
507-
508-
try:
509-
procedures = self._session.sql(
510-
f"DESCRIBE AS RESOURCE FUNCTION {db_name}.{schema_name}.{function_id}"
511-
).collect()
512-
return UserDefinedFunction.from_json(str(procedures[0][0]))
513-
except (
514-
IndexError, # when sql returned no results
515-
SnowparkSQLException, # when database, or schema doesn't exist
516-
):
517-
raise NotFoundError(
518-
f"Function with name {udf_name} and arguments {arg_types} could not be found in schema '{db_name}.{schema_name}'"
519-
)
434+
return (
435+
self._root.databases[db_name]
436+
.schemas[schema_name]
437+
.user_defined_functions[function_id]
438+
.fetch()
439+
)
520440

521441
# set methods
522442
def set_current_database(self, database: Union[str, Database]) -> None:
@@ -546,7 +466,7 @@ def database_exists(self, database: Union[str, Database]) -> bool:
546466
"""
547467
db_name = self._parse_database(database)
548468
try:
549-
self.get_database(db_name)
469+
self._root.databases[db_name].fetch()
550470
return True
551471
except NotFoundError:
552472
return False
@@ -567,7 +487,7 @@ def schema_exists(
567487
db_name = self._parse_database(database, schema)
568488
schema_name = self._parse_schema(schema)
569489
try:
570-
self.get_schema(schema=schema_name, database=db_name)
490+
self._root.databases[db_name].schemas[schema_name].fetch()
571491
return True
572492
except NotFoundError:
573493
return False
@@ -591,7 +511,9 @@ def table_exists(
591511
schema_name = self._parse_schema(schema, table)
592512
table_name = table if isinstance(table, str) else table.name
593513
try:
594-
self.get_table(table_name=table_name, database=db_name, schema=schema_name)
514+
self._root.databases[db_name].schemas[schema_name].tables[
515+
table_name
516+
].fetch()
595517
return True
596518
except NotFoundError:
597519
return False
@@ -615,7 +537,7 @@ def view_exists(
615537
schema_name = self._parse_schema(schema, view)
616538
view_name = view if isinstance(view, str) else view.name
617539
try:
618-
self.get_view(view_name=view_name, database=db_name, schema=schema_name)
540+
self._root.databases[db_name].schemas[schema_name].views[view_name].fetch()
619541
return True
620542
except NotFoundError:
621543
return False
@@ -637,24 +559,14 @@ def procedure_exists(
637559
database: database name or ``Database`` object. Defaults to None.
638560
schema: schema name or ``Schema`` object. Defaults to None.
639561
"""
562+
db_name = self._parse_database(database, procedure)
563+
schema_name = self._parse_schema(schema, procedure)
564+
procedure_id = self._parse_function_or_procedure(procedure, arg_types)
565+
640566
try:
641-
if isinstance(procedure, Procedure):
642-
if arg_types is not None or database is not None or schema is not None:
643-
raise ArgumentError(
644-
"When provided procedure is a Procedure class no other arguments can be provided"
645-
)
646-
database = procedure.database_name
647-
schema = procedure.schema_name
648-
arg_types = [
649-
type_string_to_type_object(a.datatype) for a in procedure.arguments
650-
]
651-
procedure = procedure.name
652-
self.get_procedure(
653-
procedure_name=procedure,
654-
arg_types=arg_types,
655-
database=database,
656-
schema=schema,
657-
)
567+
self._root.databases[db_name].schemas[schema_name].procedures[
568+
procedure_id
569+
].fetch()
658570
return True
659571
except NotFoundError:
660572
return False
@@ -678,24 +590,14 @@ def user_defined_function_exists(
678590
database: database name or ``Database`` object. Defaults to None.
679591
schema: schema name or ``Schema`` object. Defaults to None.
680592
"""
593+
db_name = self._parse_database(database, udf)
594+
schema_name = self._parse_schema(schema, udf)
595+
function_id = self._parse_function_or_procedure(udf, arg_types)
596+
681597
try:
682-
if isinstance(udf, UserDefinedFunction):
683-
if arg_types is not None or database is not None or schema is not None:
684-
raise ArgumentError(
685-
"When provided udf is a UserDefinedFunction class no other arguments can be provided"
686-
)
687-
database = udf.database_name
688-
schema = udf.schema_name
689-
arg_types = [
690-
type_string_to_type_object(a.datatype) for a in udf.arguments
691-
]
692-
udf = udf.name
693-
self.get_user_defined_function(
694-
udf_name=udf,
695-
arg_types=arg_types,
696-
database=database,
697-
schema=schema,
698-
)
598+
self._root.databases[db_name].schemas[schema_name].user_defined_functions[
599+
function_id
600+
].fetch()
699601
return True
700602
except NotFoundError:
701603
return False
@@ -708,7 +610,7 @@ def drop_database(self, database: Union[str, Database]) -> None:
708610
database: database name or ``Database`` object.
709611
"""
710612
db_name = self._parse_database(database)
711-
self._session.sql(f"DROP DATABASE {db_name}").collect()
613+
self._root.databases[db_name].drop()
712614

713615
def drop_schema(
714616
self,
@@ -725,7 +627,7 @@ def drop_schema(
725627
"""
726628
db_name = self._parse_database(database, schema)
727629
schema_name = self._parse_schema(schema)
728-
self._session.sql(f"DROP SCHEMA {db_name}.{schema_name}").collect()
630+
self._root.databases[db_name].schemas[schema_name].drop()
729631

730632
def drop_table(
731633
self,
@@ -746,7 +648,7 @@ def drop_table(
746648
schema_name = self._parse_schema(schema, table)
747649
table_name = table if isinstance(table, str) else table.name
748650

749-
self._session.sql(f"DROP TABLE {db_name}.{schema_name}.{table_name}").collect()
651+
self._root.databases[db_name].schemas[schema_name].tables[table_name].drop()
750652

751653
def drop_view(
752654
self,
@@ -767,7 +669,7 @@ def drop_view(
767669
schema_name = self._parse_schema(schema, view)
768670
view_name = view if isinstance(view, str) else view.name
769671

770-
self._session.sql(f"DROP VIEW {db_name}.{schema_name}.{view_name}").collect()
672+
self._root.databases[db_name].schemas[schema_name].views[view_name].drop()
771673

772674
# aliases
773675
listDatabases = list_databases

0 commit comments

Comments
 (0)