snowpark-connect 0.27.0__py3-none-any.whl → 1.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. snowflake/snowpark_connect/__init__.py +1 -0
  2. snowflake/snowpark_connect/analyze_plan/map_tree_string.py +8 -4
  3. snowflake/snowpark_connect/client/__init__.py +15 -0
  4. snowflake/snowpark_connect/client/error_utils.py +30 -0
  5. snowflake/snowpark_connect/client/exceptions.py +36 -0
  6. snowflake/snowpark_connect/client/query_results.py +90 -0
  7. snowflake/snowpark_connect/client/server.py +717 -0
  8. snowflake/snowpark_connect/client/utils/__init__.py +10 -0
  9. snowflake/snowpark_connect/client/utils/session.py +85 -0
  10. snowflake/snowpark_connect/column_name_handler.py +404 -243
  11. snowflake/snowpark_connect/column_qualifier.py +43 -0
  12. snowflake/snowpark_connect/config.py +309 -26
  13. snowflake/snowpark_connect/constants.py +2 -0
  14. snowflake/snowpark_connect/dataframe_container.py +102 -8
  15. snowflake/snowpark_connect/date_time_format_mapping.py +71 -13
  16. snowflake/snowpark_connect/error/error_codes.py +50 -0
  17. snowflake/snowpark_connect/error/error_utils.py +172 -23
  18. snowflake/snowpark_connect/error/exceptions.py +13 -4
  19. snowflake/snowpark_connect/execute_plan/map_execution_command.py +15 -160
  20. snowflake/snowpark_connect/execute_plan/map_execution_root.py +26 -20
  21. snowflake/snowpark_connect/execute_plan/utils.py +5 -1
  22. snowflake/snowpark_connect/expression/error_utils.py +28 -0
  23. snowflake/snowpark_connect/expression/function_defaults.py +9 -2
  24. snowflake/snowpark_connect/expression/hybrid_column_map.py +53 -5
  25. snowflake/snowpark_connect/expression/integral_types_support.py +219 -0
  26. snowflake/snowpark_connect/expression/literal.py +37 -13
  27. snowflake/snowpark_connect/expression/map_cast.py +224 -15
  28. snowflake/snowpark_connect/expression/map_expression.py +80 -27
  29. snowflake/snowpark_connect/expression/map_extension.py +322 -12
  30. snowflake/snowpark_connect/expression/map_sql_expression.py +316 -81
  31. snowflake/snowpark_connect/expression/map_udf.py +86 -20
  32. snowflake/snowpark_connect/expression/map_unresolved_attribute.py +451 -173
  33. snowflake/snowpark_connect/expression/map_unresolved_function.py +2964 -829
  34. snowflake/snowpark_connect/expression/map_unresolved_star.py +87 -23
  35. snowflake/snowpark_connect/expression/map_update_fields.py +70 -18
  36. snowflake/snowpark_connect/expression/map_window_function.py +18 -3
  37. snowflake/snowpark_connect/includes/jars/json4s-ast_2.13-3.7.0-M11.jar +0 -0
  38. snowflake/snowpark_connect/includes/jars/{scala-library-2.12.18.jar → sas-scala-udf_2.12-0.2.0.jar} +0 -0
  39. snowflake/snowpark_connect/includes/jars/sas-scala-udf_2.13-0.2.0.jar +0 -0
  40. snowflake/snowpark_connect/includes/jars/scala-reflect-2.13.16.jar +0 -0
  41. snowflake/snowpark_connect/includes/jars/spark-common-utils_2.13-3.5.6.jar +0 -0
  42. snowflake/snowpark_connect/includes/jars/{spark-connect-client-jvm_2.12-3.5.6.jar → spark-connect-client-jvm_2.13-3.5.6.jar} +0 -0
  43. snowflake/snowpark_connect/includes/jars/{spark-sql_2.12-3.5.6.jar → spark-sql_2.13-3.5.6.jar} +0 -0
  44. snowflake/snowpark_connect/includes/python/pyspark/sql/connect/streaming/worker/foreach_batch_worker.py +1 -1
  45. snowflake/snowpark_connect/includes/python/pyspark/sql/connect/streaming/worker/listener_worker.py +1 -1
  46. snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.py +12 -10
  47. snowflake/snowpark_connect/proto/snowflake_expression_ext_pb2.pyi +14 -2
  48. snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2.py +10 -8
  49. snowflake/snowpark_connect/proto/snowflake_relation_ext_pb2.pyi +13 -6
  50. snowflake/snowpark_connect/relation/catalogs/abstract_spark_catalog.py +65 -17
  51. snowflake/snowpark_connect/relation/catalogs/snowflake_catalog.py +297 -49
  52. snowflake/snowpark_connect/relation/catalogs/utils.py +12 -4
  53. snowflake/snowpark_connect/relation/io_utils.py +110 -10
  54. snowflake/snowpark_connect/relation/map_aggregate.py +239 -256
  55. snowflake/snowpark_connect/relation/map_catalog.py +5 -1
  56. snowflake/snowpark_connect/relation/map_column_ops.py +264 -96
  57. snowflake/snowpark_connect/relation/map_extension.py +263 -29
  58. snowflake/snowpark_connect/relation/map_join.py +683 -442
  59. snowflake/snowpark_connect/relation/map_local_relation.py +28 -1
  60. snowflake/snowpark_connect/relation/map_map_partitions.py +83 -8
  61. snowflake/snowpark_connect/relation/map_relation.py +48 -19
  62. snowflake/snowpark_connect/relation/map_row_ops.py +310 -91
  63. snowflake/snowpark_connect/relation/map_show_string.py +13 -6
  64. snowflake/snowpark_connect/relation/map_sql.py +1233 -222
  65. snowflake/snowpark_connect/relation/map_stats.py +48 -9
  66. snowflake/snowpark_connect/relation/map_subquery_alias.py +11 -2
  67. snowflake/snowpark_connect/relation/map_udtf.py +14 -4
  68. snowflake/snowpark_connect/relation/read/jdbc_read_dbapi.py +53 -14
  69. snowflake/snowpark_connect/relation/read/map_read.py +134 -43
  70. snowflake/snowpark_connect/relation/read/map_read_csv.py +326 -47
  71. snowflake/snowpark_connect/relation/read/map_read_jdbc.py +21 -6
  72. snowflake/snowpark_connect/relation/read/map_read_json.py +324 -86
  73. snowflake/snowpark_connect/relation/read/map_read_parquet.py +146 -28
  74. snowflake/snowpark_connect/relation/read/map_read_partitioned_parquet.py +142 -0
  75. snowflake/snowpark_connect/relation/read/map_read_socket.py +15 -3
  76. snowflake/snowpark_connect/relation/read/map_read_table.py +86 -6
  77. snowflake/snowpark_connect/relation/read/map_read_text.py +22 -4
  78. snowflake/snowpark_connect/relation/read/metadata_utils.py +170 -0
  79. snowflake/snowpark_connect/relation/read/reader_config.py +42 -3
  80. snowflake/snowpark_connect/relation/read/utils.py +50 -5
  81. snowflake/snowpark_connect/relation/stage_locator.py +91 -55
  82. snowflake/snowpark_connect/relation/utils.py +128 -5
  83. snowflake/snowpark_connect/relation/write/jdbc_write_dbapi.py +19 -3
  84. snowflake/snowpark_connect/relation/write/map_write.py +929 -319
  85. snowflake/snowpark_connect/relation/write/map_write_jdbc.py +8 -2
  86. snowflake/snowpark_connect/resources/java_udfs-1.0-SNAPSHOT.jar +0 -0
  87. snowflake/snowpark_connect/resources_initializer.py +171 -48
  88. snowflake/snowpark_connect/server.py +528 -473
  89. snowflake/snowpark_connect/server_common/__init__.py +503 -0
  90. snowflake/snowpark_connect/snowflake_session.py +65 -0
  91. snowflake/snowpark_connect/start_server.py +53 -5
  92. snowflake/snowpark_connect/type_mapping.py +349 -27
  93. snowflake/snowpark_connect/type_support.py +130 -0
  94. snowflake/snowpark_connect/typed_column.py +9 -7
  95. snowflake/snowpark_connect/utils/artifacts.py +9 -8
  96. snowflake/snowpark_connect/utils/cache.py +49 -27
  97. snowflake/snowpark_connect/utils/concurrent.py +36 -1
  98. snowflake/snowpark_connect/utils/context.py +195 -37
  99. snowflake/snowpark_connect/utils/describe_query_cache.py +68 -53
  100. snowflake/snowpark_connect/utils/env_utils.py +5 -1
  101. snowflake/snowpark_connect/utils/expression_transformer.py +172 -0
  102. snowflake/snowpark_connect/utils/identifiers.py +137 -3
  103. snowflake/snowpark_connect/utils/io_utils.py +57 -1
  104. snowflake/snowpark_connect/utils/java_stored_procedure.py +151 -0
  105. snowflake/snowpark_connect/utils/java_udaf_utils.py +321 -0
  106. snowflake/snowpark_connect/utils/java_udtf_utils.py +239 -0
  107. snowflake/snowpark_connect/utils/jvm_udf_utils.py +281 -0
  108. snowflake/snowpark_connect/utils/open_telemetry.py +516 -0
  109. snowflake/snowpark_connect/utils/pandas_udtf_utils.py +8 -4
  110. snowflake/snowpark_connect/utils/patch_spark_line_number.py +181 -0
  111. snowflake/snowpark_connect/utils/profiling.py +25 -8
  112. snowflake/snowpark_connect/utils/scala_udf_utils.py +185 -340
  113. snowflake/snowpark_connect/utils/sequence.py +21 -0
  114. snowflake/snowpark_connect/utils/session.py +64 -28
  115. snowflake/snowpark_connect/utils/snowpark_connect_logging.py +51 -9
  116. snowflake/snowpark_connect/utils/spcs_logger.py +290 -0
  117. snowflake/snowpark_connect/utils/telemetry.py +192 -40
  118. snowflake/snowpark_connect/utils/temporary_view_cache.py +67 -0
  119. snowflake/snowpark_connect/utils/temporary_view_helper.py +334 -0
  120. snowflake/snowpark_connect/utils/udf_cache.py +117 -41
  121. snowflake/snowpark_connect/utils/udf_helper.py +39 -37
  122. snowflake/snowpark_connect/utils/udf_utils.py +133 -14
  123. snowflake/snowpark_connect/utils/udtf_helper.py +8 -1
  124. snowflake/snowpark_connect/utils/udtf_utils.py +46 -31
  125. snowflake/snowpark_connect/utils/udxf_import_utils.py +9 -2
  126. snowflake/snowpark_connect/utils/upload_java_jar.py +57 -0
  127. snowflake/snowpark_connect/version.py +1 -1
  128. snowflake/snowpark_decoder/dp_session.py +6 -2
  129. snowflake/snowpark_decoder/spark_decoder.py +12 -0
  130. {snowpark_connect-0.27.0.data → snowpark_connect-1.7.0.data}/scripts/snowpark-submit +14 -4
  131. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/METADATA +16 -7
  132. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/RECORD +139 -168
  133. snowflake/snowpark_connect/hidden_column.py +0 -39
  134. snowflake/snowpark_connect/includes/jars/antlr4-runtime-4.9.3.jar +0 -0
  135. snowflake/snowpark_connect/includes/jars/commons-cli-1.5.0.jar +0 -0
  136. snowflake/snowpark_connect/includes/jars/commons-codec-1.16.1.jar +0 -0
  137. snowflake/snowpark_connect/includes/jars/commons-collections-3.2.2.jar +0 -0
  138. snowflake/snowpark_connect/includes/jars/commons-collections4-4.4.jar +0 -0
  139. snowflake/snowpark_connect/includes/jars/commons-compiler-3.1.9.jar +0 -0
  140. snowflake/snowpark_connect/includes/jars/commons-compress-1.26.0.jar +0 -0
  141. snowflake/snowpark_connect/includes/jars/commons-crypto-1.1.0.jar +0 -0
  142. snowflake/snowpark_connect/includes/jars/commons-dbcp-1.4.jar +0 -0
  143. snowflake/snowpark_connect/includes/jars/commons-io-2.16.1.jar +0 -0
  144. snowflake/snowpark_connect/includes/jars/commons-lang-2.6.jar +0 -0
  145. snowflake/snowpark_connect/includes/jars/commons-lang3-3.12.0.jar +0 -0
  146. snowflake/snowpark_connect/includes/jars/commons-logging-1.1.3.jar +0 -0
  147. snowflake/snowpark_connect/includes/jars/commons-math3-3.6.1.jar +0 -0
  148. snowflake/snowpark_connect/includes/jars/commons-pool-1.5.4.jar +0 -0
  149. snowflake/snowpark_connect/includes/jars/commons-text-1.10.0.jar +0 -0
  150. snowflake/snowpark_connect/includes/jars/hadoop-client-api-trimmed-3.3.4.jar +0 -0
  151. snowflake/snowpark_connect/includes/jars/jackson-annotations-2.15.2.jar +0 -0
  152. snowflake/snowpark_connect/includes/jars/jackson-core-2.15.2.jar +0 -0
  153. snowflake/snowpark_connect/includes/jars/jackson-core-asl-1.9.13.jar +0 -0
  154. snowflake/snowpark_connect/includes/jars/jackson-databind-2.15.2.jar +0 -0
  155. snowflake/snowpark_connect/includes/jars/jackson-dataformat-yaml-2.15.2.jar +0 -0
  156. snowflake/snowpark_connect/includes/jars/jackson-datatype-jsr310-2.15.2.jar +0 -0
  157. snowflake/snowpark_connect/includes/jars/jackson-module-scala_2.12-2.15.2.jar +0 -0
  158. snowflake/snowpark_connect/includes/jars/json4s-ast_2.12-3.7.0-M11.jar +0 -0
  159. snowflake/snowpark_connect/includes/jars/json4s-core_2.12-3.7.0-M11.jar +0 -0
  160. snowflake/snowpark_connect/includes/jars/json4s-jackson_2.12-3.7.0-M11.jar +0 -0
  161. snowflake/snowpark_connect/includes/jars/json4s-native_2.12-3.7.0-M11.jar +0 -0
  162. snowflake/snowpark_connect/includes/jars/json4s-scalap_2.12-3.7.0-M11.jar +0 -0
  163. snowflake/snowpark_connect/includes/jars/kryo-shaded-4.0.2.jar +0 -0
  164. snowflake/snowpark_connect/includes/jars/log4j-1.2-api-2.20.0.jar +0 -0
  165. snowflake/snowpark_connect/includes/jars/log4j-api-2.20.0.jar +0 -0
  166. snowflake/snowpark_connect/includes/jars/log4j-core-2.20.0.jar +0 -0
  167. snowflake/snowpark_connect/includes/jars/log4j-slf4j2-impl-2.20.0.jar +0 -0
  168. snowflake/snowpark_connect/includes/jars/paranamer-2.8.3.jar +0 -0
  169. snowflake/snowpark_connect/includes/jars/paranamer-2.8.jar +0 -0
  170. snowflake/snowpark_connect/includes/jars/sas-scala-udf_2.12-0.1.0.jar +0 -0
  171. snowflake/snowpark_connect/includes/jars/scala-collection-compat_2.12-2.7.0.jar +0 -0
  172. snowflake/snowpark_connect/includes/jars/scala-parser-combinators_2.12-2.3.0.jar +0 -0
  173. snowflake/snowpark_connect/includes/jars/scala-reflect-2.12.18.jar +0 -0
  174. snowflake/snowpark_connect/includes/jars/scala-xml_2.12-2.1.0.jar +0 -0
  175. snowflake/snowpark_connect/includes/jars/slf4j-api-2.0.7.jar +0 -0
  176. snowflake/snowpark_connect/includes/jars/spark-catalyst_2.12-3.5.6.jar +0 -0
  177. snowflake/snowpark_connect/includes/jars/spark-common-utils_2.12-3.5.6.jar +0 -0
  178. snowflake/snowpark_connect/includes/jars/spark-core_2.12-3.5.6.jar +0 -0
  179. snowflake/snowpark_connect/includes/jars/spark-graphx_2.12-3.5.6.jar +0 -0
  180. snowflake/snowpark_connect/includes/jars/spark-hive-thriftserver_2.12-3.5.6.jar +0 -0
  181. snowflake/snowpark_connect/includes/jars/spark-hive_2.12-3.5.6.jar +0 -0
  182. snowflake/snowpark_connect/includes/jars/spark-kvstore_2.12-3.5.6.jar +0 -0
  183. snowflake/snowpark_connect/includes/jars/spark-launcher_2.12-3.5.6.jar +0 -0
  184. snowflake/snowpark_connect/includes/jars/spark-mesos_2.12-3.5.6.jar +0 -0
  185. snowflake/snowpark_connect/includes/jars/spark-mllib-local_2.12-3.5.6.jar +0 -0
  186. snowflake/snowpark_connect/includes/jars/spark-network-common_2.12-3.5.6.jar +0 -0
  187. snowflake/snowpark_connect/includes/jars/spark-network-shuffle_2.12-3.5.6.jar +0 -0
  188. snowflake/snowpark_connect/includes/jars/spark-repl_2.12-3.5.6.jar +0 -0
  189. snowflake/snowpark_connect/includes/jars/spark-sketch_2.12-3.5.6.jar +0 -0
  190. snowflake/snowpark_connect/includes/jars/spark-sql-api_2.12-3.5.6.jar +0 -0
  191. snowflake/snowpark_connect/includes/jars/spark-tags_2.12-3.5.6.jar +0 -0
  192. snowflake/snowpark_connect/includes/jars/spark-unsafe_2.12-3.5.6.jar +0 -0
  193. snowflake/snowpark_connect/includes/jars/spark-yarn_2.12-3.5.6.jar +0 -0
  194. {snowpark_connect-0.27.0.data → snowpark_connect-1.7.0.data}/scripts/snowpark-connect +0 -0
  195. {snowpark_connect-0.27.0.data → snowpark_connect-1.7.0.data}/scripts/snowpark-session +0 -0
  196. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/WHEEL +0 -0
  197. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/licenses/LICENSE-binary +0 -0
  198. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
  199. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/licenses/NOTICE-binary +0 -0
  200. {snowpark_connect-0.27.0.dist-info → snowpark_connect-1.7.0.dist-info}/top_level.txt +0 -0
@@ -8,23 +8,29 @@ import typing
8
8
  import pandas
9
9
  import pyspark.sql.connect.proto.common_pb2 as common_proto
10
10
  import pyspark.sql.connect.proto.types_pb2 as types_proto
11
+ from pyspark.errors.exceptions.base import AnalysisException
11
12
  from pyspark.sql.connect.client.core import Retrying
12
13
  from snowflake.core.exceptions import APIError, NotFoundError
13
14
  from snowflake.core.schema import Schema
14
15
  from snowflake.core.table import Table, TableColumn
15
16
 
16
- from snowflake.snowpark import functions
17
17
  from snowflake.snowpark._internal.analyzer.analyzer_utils import (
18
18
  quote_name_without_upper_casing,
19
19
  unquote_if_quoted,
20
20
  )
21
21
  from snowflake.snowpark.functions import lit
22
22
  from snowflake.snowpark.types import BooleanType, StringType
23
+ from snowflake.snowpark_connect.column_qualifier import ColumnQualifier
23
24
  from snowflake.snowpark_connect.config import (
24
25
  auto_uppercase_non_column_identifiers,
25
26
  global_config,
26
27
  )
27
28
  from snowflake.snowpark_connect.dataframe_container import DataFrameContainer
29
+ from snowflake.snowpark_connect.error.error_codes import ErrorCodes
30
+ from snowflake.snowpark_connect.error.error_utils import (
31
+ TABLE_OR_VIEW_NOT_FOUND_ERROR_CLASS,
32
+ attach_custom_error_code,
33
+ )
28
34
  from snowflake.snowpark_connect.error.exceptions import MaxRetryExceeded
29
35
  from snowflake.snowpark_connect.relation.catalogs.abstract_spark_catalog import (
30
36
  AbstractSparkCatalog,
@@ -34,12 +40,19 @@ from snowflake.snowpark_connect.relation.catalogs.abstract_spark_catalog import
34
40
  )
35
41
  from snowflake.snowpark_connect.type_mapping import proto_to_snowpark_type
36
42
  from snowflake.snowpark_connect.utils.identifiers import (
43
+ FQN,
44
+ spark_to_sf_single_id_with_unquoting,
37
45
  split_fully_qualified_spark_name,
38
46
  )
39
47
  from snowflake.snowpark_connect.utils.session import get_or_create_snowpark_session
40
48
  from snowflake.snowpark_connect.utils.telemetry import (
41
49
  SnowparkConnectNotImplementedError,
42
50
  )
51
+ from snowflake.snowpark_connect.utils.temporary_view_helper import (
52
+ get_temp_view,
53
+ get_temp_view_normalized_names,
54
+ unregister_temp_view,
55
+ )
43
56
  from snowflake.snowpark_connect.utils.udf_cache import cached_udf
44
57
 
45
58
 
@@ -103,9 +116,11 @@ class SnowflakeCatalog(AbstractSparkCatalog):
103
116
  catalog, sf_database, sf_schema = _process_multi_layer_database(pattern)
104
117
  sf_schema = sf_schema.replace("*", ".*")
105
118
  if catalog is not None and self != catalog:
106
- raise SnowparkConnectNotImplementedError(
119
+ exception = SnowparkConnectNotImplementedError(
107
120
  "Calling into another catalog is not currently supported"
108
121
  )
122
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
123
+ raise exception
109
124
  sp_catalog = get_or_create_snowpark_session().catalog
110
125
 
111
126
  dbs: list[Schema] | None = None
@@ -125,7 +140,8 @@ class SnowflakeCatalog(AbstractSparkCatalog):
125
140
  )
126
141
  if dbs is None:
127
142
  raise MaxRetryExceeded(
128
- f"Failed to fetch databases {f'with pattern {pattern} ' if pattern is not None else ''}after all retry attempts"
143
+ f"Failed to fetch databases {f'with pattern {pattern} ' if pattern is not None else ''}after all retry attempts",
144
+ custom_error_code=ErrorCodes.INTERNAL_ERROR,
129
145
  )
130
146
  names: list[str] = list()
131
147
  catalogs: list[str] = list()
@@ -157,9 +173,11 @@ class SnowflakeCatalog(AbstractSparkCatalog):
157
173
  """Listing a single database that's accessible in Snowflake."""
158
174
  catalog, sf_database, sf_schema = _process_multi_layer_database(spark_dbName)
159
175
  if catalog is not None and self != catalog:
160
- raise SnowparkConnectNotImplementedError(
176
+ exception = SnowparkConnectNotImplementedError(
161
177
  "Calling into another catalog is not currently supported"
162
178
  )
179
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
180
+ raise exception
163
181
  sp_catalog = get_or_create_snowpark_session().catalog
164
182
 
165
183
  db: Schema | None = None
@@ -178,7 +196,8 @@ class SnowflakeCatalog(AbstractSparkCatalog):
178
196
  )
179
197
  if db is None:
180
198
  raise MaxRetryExceeded(
181
- f"Failed to fetch database {spark_dbName} after all retry attempts"
199
+ f"Failed to fetch database {spark_dbName} after all retry attempts",
200
+ custom_error_code=ErrorCodes.INTERNAL_ERROR,
182
201
  )
183
202
 
184
203
  name = unquote_if_quoted(db.name)
@@ -203,6 +222,93 @@ class SnowflakeCatalog(AbstractSparkCatalog):
203
222
  exists = False
204
223
  return pandas.DataFrame({"exists": [exists]})
205
224
 
225
+ def _get_temp_view_prefixes(self, spark_dbName: str | None) -> list[str]:
226
+ if spark_dbName is None:
227
+ return []
228
+ return [
229
+ quote_name_without_upper_casing(part)
230
+ for part in split_fully_qualified_spark_name(spark_dbName)
231
+ ]
232
+
233
+ def _list_temp_views(
234
+ self,
235
+ spark_dbName: str | None = None,
236
+ pattern: str | None = None,
237
+ ) -> typing.Tuple[
238
+ list[str | None],
239
+ list[list[str | None]],
240
+ list[str],
241
+ list[str | None],
242
+ list[str | None],
243
+ list[bool],
244
+ ]:
245
+ catalogs: list[str | None] = list()
246
+ namespaces: list[list[str | None]] = list()
247
+ names: list[str] = list()
248
+ descriptions: list[str | None] = list()
249
+ table_types: list[str | None] = list()
250
+ is_temporaries: list[bool] = list()
251
+
252
+ temp_views_prefix = ".".join(self._get_temp_view_prefixes(spark_dbName))
253
+ normalized_spark_dbName = (
254
+ temp_views_prefix.lower()
255
+ if global_config.spark_sql_caseSensitive
256
+ else temp_views_prefix
257
+ )
258
+ normalized_global_temp_database_name = (
259
+ quote_name_without_upper_casing(
260
+ global_config.spark_sql_globalTempDatabase.lower()
261
+ )
262
+ if global_config.spark_sql_caseSensitive
263
+ else quote_name_without_upper_casing(
264
+ global_config.spark_sql_globalTempDatabase
265
+ )
266
+ )
267
+
268
+ temp_views = get_temp_view_normalized_names()
269
+ null_safe_pattern = pattern if pattern is not None else ""
270
+
271
+ for temp_view in temp_views:
272
+ normalized_temp_view = (
273
+ temp_view.lower()
274
+ if global_config.spark_sql_caseSensitive
275
+ else temp_view
276
+ )
277
+ fqn = FQN.from_string(temp_view)
278
+ normalized_schema = (
279
+ fqn.schema.lower()
280
+ if fqn.schema is not None and global_config.spark_sql_caseSensitive
281
+ else fqn.schema
282
+ )
283
+
284
+ is_global_view = normalized_global_temp_database_name == normalized_schema
285
+ is_local_temp_view = fqn.schema is None
286
+ # Temporary views are always shown if they match the pattern
287
+ matches_prefix = (
288
+ normalized_spark_dbName == normalized_schema or is_local_temp_view
289
+ )
290
+ if matches_prefix and bool(
291
+ re.match(null_safe_pattern, normalized_temp_view)
292
+ ):
293
+ names.append(unquote_if_quoted(fqn.name))
294
+ catalogs.append(None)
295
+ namespaces.append(
296
+ [global_config.spark_sql_globalTempDatabase]
297
+ if is_global_view
298
+ else []
299
+ )
300
+ descriptions.append(None)
301
+ table_types.append("TEMPORARY")
302
+ is_temporaries.append(True)
303
+ return (
304
+ catalogs,
305
+ namespaces,
306
+ names,
307
+ descriptions,
308
+ table_types,
309
+ is_temporaries,
310
+ )
311
+
206
312
  def listTables(
207
313
  self,
208
314
  spark_dbName: str | None = None,
@@ -214,9 +320,11 @@ class SnowflakeCatalog(AbstractSparkCatalog):
214
320
  spark_dbName
215
321
  )
216
322
  if catalog is not None and self != catalog:
217
- raise SnowparkConnectNotImplementedError(
323
+ exception = SnowparkConnectNotImplementedError(
218
324
  "Calling into another catalog is not currently supported"
219
325
  )
326
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
327
+ raise exception
220
328
  else:
221
329
  catalog = sf_database = sf_schema = None
222
330
 
@@ -232,8 +340,7 @@ class SnowflakeCatalog(AbstractSparkCatalog):
232
340
  schema=sf_quote(sf_schema),
233
341
  pattern=_normalize_identifier(pattern),
234
342
  )
235
- names: list[str] = list()
236
- catalogs: list[str] = list()
343
+ catalogs: list[str | None] = list()
237
344
  namespaces: list[list[str | None]] = list()
238
345
  names: list[str] = list()
239
346
  descriptions: list[str | None] = list()
@@ -253,6 +360,22 @@ class SnowflakeCatalog(AbstractSparkCatalog):
253
360
  descriptions.append(o[6] if o[6] else None)
254
361
  table_types.append("PERMANENT")
255
362
  is_temporaries.append(False)
363
+
364
+ (
365
+ non_materialized_catalogs,
366
+ non_materialized_namespaces,
367
+ non_materialized_names,
368
+ non_materialized_descriptions,
369
+ non_materialized_table_types,
370
+ non_materialized_is_temporaries,
371
+ ) = self._list_temp_views(spark_dbName, pattern)
372
+ catalogs.extend(non_materialized_catalogs)
373
+ namespaces.extend(non_materialized_namespaces)
374
+ names.extend(non_materialized_names)
375
+ descriptions.extend(non_materialized_descriptions)
376
+ table_types.extend(non_materialized_table_types)
377
+ is_temporaries.extend(non_materialized_is_temporaries)
378
+
256
379
  return pandas.DataFrame(
257
380
  {
258
381
  "name": names,
@@ -297,35 +420,76 @@ class SnowflakeCatalog(AbstractSparkCatalog):
297
420
  spark_tableName: str,
298
421
  ) -> pandas.DataFrame:
299
422
  """Listing a single table/view with provided name that's accessible in Snowflake."""
423
+
424
+ def _get_temp_view():
425
+ spark_table_name_parts = [
426
+ quote_name_without_upper_casing(part)
427
+ for part in split_fully_qualified_spark_name(spark_tableName)
428
+ ]
429
+ spark_view_name = ".".join(spark_table_name_parts)
430
+ temp_view = get_temp_view(spark_view_name)
431
+ if temp_view:
432
+ return pandas.DataFrame(
433
+ {
434
+ "name": [unquote_if_quoted(spark_table_name_parts[-1])],
435
+ "catalog": [None],
436
+ "namespace": [
437
+ [unquote_if_quoted(spark_table_name_parts[-2])]
438
+ if len(spark_table_name_parts) > 1
439
+ else []
440
+ ],
441
+ "description": [None],
442
+ "tableType": ["TEMPORARY"],
443
+ "isTemporary": [True],
444
+ }
445
+ )
446
+ return None
447
+
448
+ # Attempt to get the view from the non materialized views first
449
+ temp_view = _get_temp_view()
450
+ if temp_view is not None:
451
+ return temp_view
452
+
300
453
  sp_catalog = get_or_create_snowpark_session().catalog
301
454
  catalog, sf_database, sf_schema, table_name = _process_multi_layer_identifier(
302
455
  spark_tableName
303
456
  )
304
457
  if catalog is not None and self != catalog:
305
- raise SnowparkConnectNotImplementedError(
458
+ exception = SnowparkConnectNotImplementedError(
306
459
  "Calling into another catalog is not currently supported"
307
460
  )
461
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
462
+ raise exception
308
463
 
309
464
  table: Table | None = None
310
- for attempt in Retrying(
311
- max_retries=5,
312
- initial_backoff=100, # 100ms
313
- max_backoff=5000, # 5 s
314
- backoff_multiplier=2.0,
315
- jitter=100,
316
- min_jitter_threshold=200,
317
- can_retry=_is_retryable_api_error,
318
- ):
319
- with attempt:
320
- table = sp_catalog.get_table(
321
- database=sf_quote(sf_database),
322
- schema=sf_quote(sf_schema),
323
- table_name=sf_quote(table_name),
324
- )
465
+ try:
466
+ for attempt in Retrying(
467
+ max_retries=5,
468
+ initial_backoff=100, # 100ms
469
+ max_backoff=5000, # 5 s
470
+ backoff_multiplier=2.0,
471
+ jitter=100,
472
+ min_jitter_threshold=200,
473
+ can_retry=_is_retryable_api_error,
474
+ ):
475
+ with attempt:
476
+ table = sp_catalog.get_table(
477
+ database=sf_quote(sf_database),
478
+ schema=sf_quote(sf_schema),
479
+ table_name=sf_quote(table_name),
480
+ )
481
+ except NotFoundError:
482
+ exception = AnalysisException(
483
+ error_class=TABLE_OR_VIEW_NOT_FOUND_ERROR_CLASS,
484
+ message_parameters={"relationName": spark_tableName},
485
+ )
486
+ attach_custom_error_code(exception, ErrorCodes.TABLE_NOT_FOUND)
487
+ raise exception
325
488
 
326
489
  if table is None:
327
490
  raise MaxRetryExceeded(
328
- f"Failed to fetch table {spark_tableName} after all retry attempts"
491
+ f"Failed to fetch table {spark_tableName} after all retry attempts",
492
+ custom_error_code=ErrorCodes.INTERNAL_ERROR,
329
493
  )
330
494
 
331
495
  return pandas.DataFrame(
@@ -356,16 +520,74 @@ class SnowflakeCatalog(AbstractSparkCatalog):
356
520
  try:
357
521
  self.getTable(table_mli)
358
522
  exists = True
359
- except NotFoundError:
360
- exists = False
523
+ except AnalysisException as ex:
524
+ if ex.error_class == TABLE_OR_VIEW_NOT_FOUND_ERROR_CLASS:
525
+ exists = False
361
526
  return pandas.DataFrame({"exists": [exists]})
362
527
 
528
+ def _list_temp_view_columns(
529
+ self,
530
+ spark_tableName: str,
531
+ spark_dbName: typing.Optional[str] = None,
532
+ ):
533
+ spark_view_name_parts = [
534
+ quote_name_without_upper_casing(part)
535
+ for part in split_fully_qualified_spark_name(spark_tableName)
536
+ ]
537
+ spark_view_name_parts = (
538
+ self._get_temp_view_prefixes(spark_dbName) + spark_view_name_parts
539
+ )
540
+ spark_view_name = ".".join(spark_view_name_parts)
541
+ temp_view = get_temp_view(spark_view_name)
542
+
543
+ if not temp_view:
544
+ return None
545
+
546
+ return self._list_columns_from_dataframe_container(temp_view)
547
+
548
+ def _list_columns_from_dataframe_container(
549
+ self, container: DataFrameContainer
550
+ ) -> pandas.DataFrame:
551
+ names: list[str] = list()
552
+ descriptions: list[str | None] = list()
553
+ data_types: list[str] = list()
554
+ nullables: list[bool] = list()
555
+ is_partitions: list[bool] = list()
556
+ is_buckets: list[bool] = list()
557
+
558
+ for field, spark_column in zip(
559
+ container.dataframe.schema.fields,
560
+ container.column_map.get_spark_columns(),
561
+ ):
562
+ names.append(spark_column)
563
+ descriptions.append(None)
564
+ data_types.append(field.datatype.simpleString())
565
+ nullables.append(field.nullable)
566
+ is_partitions.append(False)
567
+ is_buckets.append(False)
568
+
569
+ return pandas.DataFrame(
570
+ {
571
+ "name": names,
572
+ "description": descriptions,
573
+ "dataType": data_types,
574
+ "nullable": nullables,
575
+ "isPartition": is_partitions,
576
+ "isBucket": is_buckets,
577
+ }
578
+ )
579
+
363
580
  def listColumns(
364
581
  self,
365
582
  spark_tableName: str,
366
583
  spark_dbName: typing.Optional[str] = None,
367
584
  ) -> pandas.DataFrame:
368
585
  """List all columns in a table/view, optionally database name filter can be provided."""
586
+
587
+ temp_view_columns = self._list_temp_view_columns(spark_tableName, spark_dbName)
588
+ if temp_view_columns is not None:
589
+ return temp_view_columns
590
+
369
591
  sp_catalog = get_or_create_snowpark_session().catalog
370
592
  columns: list[TableColumn] | None = None
371
593
  if spark_dbName is None:
@@ -373,9 +595,11 @@ class SnowflakeCatalog(AbstractSparkCatalog):
373
595
  spark_tableName
374
596
  )
375
597
  if catalog is not None and self != catalog:
376
- raise SnowparkConnectNotImplementedError(
598
+ exception = SnowparkConnectNotImplementedError(
377
599
  "Calling into another catalog is not currently supported"
378
600
  )
601
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
602
+ raise exception
379
603
  for attempt in Retrying(
380
604
  max_retries=5,
381
605
  initial_backoff=100, # 100ms
@@ -408,7 +632,8 @@ class SnowflakeCatalog(AbstractSparkCatalog):
408
632
  )
409
633
  if columns is None:
410
634
  raise MaxRetryExceeded(
411
- f"Failed to fetch columns of {spark_tableName} after all retry attempts"
635
+ f"Failed to fetch columns of {spark_tableName} after all retry attempts",
636
+ custom_error_code=ErrorCodes.INTERNAL_ERROR,
412
637
  )
413
638
  names: list[str] = list()
414
639
  descriptions: list[str | None] = list()
@@ -456,16 +681,23 @@ class SnowflakeCatalog(AbstractSparkCatalog):
456
681
  ) -> DataFrameContainer:
457
682
  session = get_or_create_snowpark_session()
458
683
  schema = global_config.spark_sql_globalTempDatabase
459
- result_df = session.sql(
460
- "drop view if exists identifier(?)",
461
- params=[f"{sf_quote(schema)}.{sf_quote(spark_view_name)}"],
462
- )
463
- result_df = result_df.select(
464
- functions.contains('"status"', functions.lit("successfully dropped")).alias(
465
- "value"
684
+ result = False
685
+ if spark_view_name:
686
+ result = unregister_temp_view(
687
+ f"{spark_to_sf_single_id_with_unquoting(schema)}.{spark_to_sf_single_id_with_unquoting(spark_view_name)}"
688
+ )
689
+
690
+ if not result:
691
+ drop_result = session.sql(
692
+ "drop view if exists identifier(?)",
693
+ params=[f"{sf_quote(schema)}.{sf_quote(spark_view_name)}"],
694
+ ).collect()
695
+ result = (
696
+ len(drop_result) == 1
697
+ and "successfully dropped" in drop_result[0]["status"]
466
698
  )
467
- )
468
699
  columns = ["value"]
700
+ result_df = session.createDataFrame([result], schema=columns)
469
701
  return DataFrameContainer.create_with_column_mapping(
470
702
  dataframe=result_df,
471
703
  spark_column_names=columns,
@@ -479,15 +711,23 @@ class SnowflakeCatalog(AbstractSparkCatalog):
479
711
  ) -> DataFrameContainer:
480
712
  """Drop the current temporary view."""
481
713
  session = get_or_create_snowpark_session()
482
- result = session.sql(
483
- "drop view if exists identifier(?)",
484
- params=[sf_quote(spark_view_name)],
485
- ).collect()
486
- view_was_dropped = (
487
- len(result) == 1 and "successfully dropped" in result[0]["status"]
488
- )
489
- result_df = session.createDataFrame([(view_was_dropped,)], schema=["value"])
490
714
  columns = ["value"]
715
+ result = False
716
+ if spark_view_name:
717
+ result = unregister_temp_view(
718
+ spark_to_sf_single_id_with_unquoting(spark_view_name)
719
+ )
720
+ if not result:
721
+ drop_result = session.sql(
722
+ "drop view if exists identifier(?)",
723
+ params=[sf_quote(spark_view_name)],
724
+ ).collect()
725
+ result = (
726
+ len(drop_result) == 1
727
+ and "successfully dropped" in drop_result[0]["status"]
728
+ )
729
+
730
+ result_df = session.createDataFrame([result], schema=columns)
491
731
  return DataFrameContainer.create_with_column_mapping(
492
732
  dataframe=result_df,
493
733
  spark_column_names=columns,
@@ -515,26 +755,34 @@ class SnowflakeCatalog(AbstractSparkCatalog):
515
755
  if source == "":
516
756
  source = global_config.get("spark.sql.sources.default")
517
757
  if source not in ("csv", "json", "avro", "parquet", "orc", "xml"):
518
- raise SnowparkConnectNotImplementedError(
758
+ exception = SnowparkConnectNotImplementedError(
519
759
  f"Source '{source}' is not currently supported by Catalog.createTable. "
520
760
  "Maybe default value through 'spark.sql.sources.default' should be set."
521
761
  )
762
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
763
+ raise exception
522
764
  if path != "":
523
765
  # External table creation is not supported currently.
524
- raise SnowparkConnectNotImplementedError(
766
+ exception = SnowparkConnectNotImplementedError(
525
767
  "External table creation is not supported currently."
526
768
  )
769
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
770
+ raise exception
527
771
 
528
772
  session = get_or_create_snowpark_session()
529
773
  # Managed table
530
774
  if schema.ByteSize() == 0:
531
- raise SnowparkConnectNotImplementedError(
775
+ exception = SnowparkConnectNotImplementedError(
532
776
  f"Unable to infer schema for {source.upper()}. It must be specified manually.",
533
777
  )
778
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
779
+ raise exception
534
780
  sp_schema = proto_to_snowpark_type(schema)
535
781
  columns = [c.name for c in schema.struct.fields]
536
782
  table_name_parts = split_fully_qualified_spark_name(tableName)
537
- qualifiers = [table_name_parts for _ in columns]
783
+ qualifiers: list[set[ColumnQualifier]] = [
784
+ {ColumnQualifier(tuple(table_name_parts))} for _ in columns
785
+ ]
538
786
  column_types = [f.datatype for f in sp_schema.fields]
539
787
  return DataFrameContainer.create_with_column_mapping(
540
788
  dataframe=session.createDataFrame([], sp_schema),
@@ -5,6 +5,8 @@
5
5
  from collections import defaultdict
6
6
 
7
7
  from snowflake.connector.errors import ProgrammingError
8
+ from snowflake.snowpark_connect.error.error_codes import ErrorCodes
9
+ from snowflake.snowpark_connect.error.error_utils import attach_custom_error_code
8
10
  from snowflake.snowpark_connect.relation.catalogs import CATALOGS, SNOWFLAKE_CATALOG
9
11
  from snowflake.snowpark_connect.relation.catalogs.abstract_spark_catalog import (
10
12
  AbstractSparkCatalog,
@@ -27,11 +29,15 @@ def set_current_catalog(catalog_name: str | None) -> AbstractSparkCatalog:
27
29
 
28
30
  # Validate input parameters to match PySpark behavior
29
31
  if catalog_name is None:
30
- raise ValueError("Catalog name cannot be None")
32
+ exception = ValueError("Catalog name cannot be None")
33
+ attach_custom_error_code(exception, ErrorCodes.INVALID_INPUT)
34
+ raise exception
31
35
  if catalog_name == "":
32
- raise ValueError(
36
+ exception = ValueError(
33
37
  "Catalog '' plugin class not found: spark.sql.catalog. is not defined"
34
38
  )
39
+ attach_custom_error_code(exception, ErrorCodes.INTERNAL_ERROR)
40
+ raise exception
35
41
 
36
42
  CURRENT_CATALOG_NAME = catalog_name
37
43
  if catalog_name in CATALOGS:
@@ -42,9 +48,11 @@ def set_current_catalog(catalog_name: str | None) -> AbstractSparkCatalog:
42
48
  sf_catalog.setCurrentDatabase(catalog_name if catalog_name is not None else "")
43
49
  return get_current_catalog()
44
50
  except ProgrammingError as e:
45
- raise Exception(
51
+ exception = Exception(
46
52
  f"Catalog '{catalog_name}' plugin class not found: spark.sql.catalog.{catalog_name} is not defined"
47
- ) from e
53
+ )
54
+ attach_custom_error_code(exception, ErrorCodes.INSUFFICIENT_INPUT)
55
+ raise exception from e
48
56
 
49
57
 
50
58
  def _get_current_temp_objects() -> set[tuple[str | None, str | None, str]]: