snowpark-connect 0.32.0__py3-none-any.whl → 0.33.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.

Potentially problematic release.


This version of snowpark-connect might be problematic. Click here for more details.

Files changed (98) hide show
  1. snowflake/snowpark_connect/column_name_handler.py +92 -27
  2. snowflake/snowpark_connect/column_qualifier.py +0 -4
  3. snowflake/snowpark_connect/expression/hybrid_column_map.py +5 -4
  4. snowflake/snowpark_connect/expression/map_sql_expression.py +12 -4
  5. snowflake/snowpark_connect/expression/map_unresolved_attribute.py +58 -21
  6. snowflake/snowpark_connect/expression/map_unresolved_function.py +62 -27
  7. snowflake/snowpark_connect/includes/python/pyspark/pandas/spark/__init__.py +16 -0
  8. snowflake/snowpark_connect/includes/python/pyspark/pandas/spark/accessors.py +1281 -0
  9. snowflake/snowpark_connect/includes/python/pyspark/pandas/spark/functions.py +203 -0
  10. snowflake/snowpark_connect/includes/python/pyspark/pandas/spark/utils.py +202 -0
  11. snowflake/snowpark_connect/relation/map_aggregate.py +2 -4
  12. snowflake/snowpark_connect/relation/map_column_ops.py +5 -0
  13. snowflake/snowpark_connect/relation/map_join.py +218 -146
  14. snowflake/snowpark_connect/relation/map_row_ops.py +136 -54
  15. snowflake/snowpark_connect/relation/map_sql.py +102 -16
  16. snowflake/snowpark_connect/relation/read/map_read_json.py +87 -2
  17. snowflake/snowpark_connect/relation/utils.py +46 -0
  18. snowflake/snowpark_connect/relation/write/map_write.py +186 -275
  19. snowflake/snowpark_connect/resources_initializer.py +25 -13
  20. snowflake/snowpark_connect/server.py +9 -24
  21. snowflake/snowpark_connect/type_mapping.py +2 -0
  22. snowflake/snowpark_connect/typed_column.py +2 -2
  23. snowflake/snowpark_connect/utils/sequence.py +21 -0
  24. snowflake/snowpark_connect/utils/session.py +8 -1
  25. snowflake/snowpark_connect/version.py +1 -1
  26. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/METADATA +3 -1
  27. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/RECORD +35 -93
  28. snowflake/snowpark_connect/includes/jars/antlr4-runtime-4.9.3.jar +0 -0
  29. snowflake/snowpark_connect/includes/jars/commons-cli-1.5.0.jar +0 -0
  30. snowflake/snowpark_connect/includes/jars/commons-codec-1.16.1.jar +0 -0
  31. snowflake/snowpark_connect/includes/jars/commons-collections-3.2.2.jar +0 -0
  32. snowflake/snowpark_connect/includes/jars/commons-collections4-4.4.jar +0 -0
  33. snowflake/snowpark_connect/includes/jars/commons-compiler-3.1.9.jar +0 -0
  34. snowflake/snowpark_connect/includes/jars/commons-compress-1.26.0.jar +0 -0
  35. snowflake/snowpark_connect/includes/jars/commons-crypto-1.1.0.jar +0 -0
  36. snowflake/snowpark_connect/includes/jars/commons-dbcp-1.4.jar +0 -0
  37. snowflake/snowpark_connect/includes/jars/commons-io-2.16.1.jar +0 -0
  38. snowflake/snowpark_connect/includes/jars/commons-lang-2.6.jar +0 -0
  39. snowflake/snowpark_connect/includes/jars/commons-lang3-3.12.0.jar +0 -0
  40. snowflake/snowpark_connect/includes/jars/commons-logging-1.1.3.jar +0 -0
  41. snowflake/snowpark_connect/includes/jars/commons-math3-3.6.1.jar +0 -0
  42. snowflake/snowpark_connect/includes/jars/commons-pool-1.5.4.jar +0 -0
  43. snowflake/snowpark_connect/includes/jars/commons-text-1.10.0.jar +0 -0
  44. snowflake/snowpark_connect/includes/jars/hadoop-client-api-trimmed-3.3.4.jar +0 -0
  45. snowflake/snowpark_connect/includes/jars/jackson-annotations-2.15.2.jar +0 -0
  46. snowflake/snowpark_connect/includes/jars/jackson-core-2.15.2.jar +0 -0
  47. snowflake/snowpark_connect/includes/jars/jackson-core-asl-1.9.13.jar +0 -0
  48. snowflake/snowpark_connect/includes/jars/jackson-databind-2.15.2.jar +0 -0
  49. snowflake/snowpark_connect/includes/jars/jackson-dataformat-yaml-2.15.2.jar +0 -0
  50. snowflake/snowpark_connect/includes/jars/jackson-datatype-jsr310-2.15.2.jar +0 -0
  51. snowflake/snowpark_connect/includes/jars/jackson-module-scala_2.12-2.15.2.jar +0 -0
  52. snowflake/snowpark_connect/includes/jars/json4s-ast_2.12-3.7.0-M11.jar +0 -0
  53. snowflake/snowpark_connect/includes/jars/json4s-core_2.12-3.7.0-M11.jar +0 -0
  54. snowflake/snowpark_connect/includes/jars/json4s-jackson_2.12-3.7.0-M11.jar +0 -0
  55. snowflake/snowpark_connect/includes/jars/json4s-native_2.12-3.7.0-M11.jar +0 -0
  56. snowflake/snowpark_connect/includes/jars/json4s-scalap_2.12-3.7.0-M11.jar +0 -0
  57. snowflake/snowpark_connect/includes/jars/kryo-shaded-4.0.2.jar +0 -0
  58. snowflake/snowpark_connect/includes/jars/log4j-1.2-api-2.20.0.jar +0 -0
  59. snowflake/snowpark_connect/includes/jars/log4j-api-2.20.0.jar +0 -0
  60. snowflake/snowpark_connect/includes/jars/log4j-core-2.20.0.jar +0 -0
  61. snowflake/snowpark_connect/includes/jars/log4j-slf4j2-impl-2.20.0.jar +0 -0
  62. snowflake/snowpark_connect/includes/jars/paranamer-2.8.3.jar +0 -0
  63. snowflake/snowpark_connect/includes/jars/paranamer-2.8.jar +0 -0
  64. snowflake/snowpark_connect/includes/jars/sas-scala-udf_2.12-0.1.0.jar +0 -0
  65. snowflake/snowpark_connect/includes/jars/scala-collection-compat_2.12-2.7.0.jar +0 -0
  66. snowflake/snowpark_connect/includes/jars/scala-library-2.12.18.jar +0 -0
  67. snowflake/snowpark_connect/includes/jars/scala-parser-combinators_2.12-2.3.0.jar +0 -0
  68. snowflake/snowpark_connect/includes/jars/scala-reflect-2.12.18.jar +0 -0
  69. snowflake/snowpark_connect/includes/jars/scala-xml_2.12-2.1.0.jar +0 -0
  70. snowflake/snowpark_connect/includes/jars/slf4j-api-2.0.7.jar +0 -0
  71. snowflake/snowpark_connect/includes/jars/spark-catalyst_2.12-3.5.6.jar +0 -0
  72. snowflake/snowpark_connect/includes/jars/spark-common-utils_2.12-3.5.6.jar +0 -0
  73. snowflake/snowpark_connect/includes/jars/spark-connect-client-jvm_2.12-3.5.6.jar +0 -0
  74. snowflake/snowpark_connect/includes/jars/spark-core_2.12-3.5.6.jar +0 -0
  75. snowflake/snowpark_connect/includes/jars/spark-graphx_2.12-3.5.6.jar +0 -0
  76. snowflake/snowpark_connect/includes/jars/spark-hive-thriftserver_2.12-3.5.6.jar +0 -0
  77. snowflake/snowpark_connect/includes/jars/spark-hive_2.12-3.5.6.jar +0 -0
  78. snowflake/snowpark_connect/includes/jars/spark-kvstore_2.12-3.5.6.jar +0 -0
  79. snowflake/snowpark_connect/includes/jars/spark-launcher_2.12-3.5.6.jar +0 -0
  80. snowflake/snowpark_connect/includes/jars/spark-mesos_2.12-3.5.6.jar +0 -0
  81. snowflake/snowpark_connect/includes/jars/spark-mllib-local_2.12-3.5.6.jar +0 -0
  82. snowflake/snowpark_connect/includes/jars/spark-network-common_2.12-3.5.6.jar +0 -0
  83. snowflake/snowpark_connect/includes/jars/spark-network-shuffle_2.12-3.5.6.jar +0 -0
  84. snowflake/snowpark_connect/includes/jars/spark-repl_2.12-3.5.6.jar +0 -0
  85. snowflake/snowpark_connect/includes/jars/spark-sketch_2.12-3.5.6.jar +0 -0
  86. snowflake/snowpark_connect/includes/jars/spark-sql-api_2.12-3.5.6.jar +0 -0
  87. snowflake/snowpark_connect/includes/jars/spark-sql_2.12-3.5.6.jar +0 -0
  88. snowflake/snowpark_connect/includes/jars/spark-tags_2.12-3.5.6.jar +0 -0
  89. snowflake/snowpark_connect/includes/jars/spark-unsafe_2.12-3.5.6.jar +0 -0
  90. snowflake/snowpark_connect/includes/jars/spark-yarn_2.12-3.5.6.jar +0 -0
  91. {snowpark_connect-0.32.0.data → snowpark_connect-0.33.0.data}/scripts/snowpark-connect +0 -0
  92. {snowpark_connect-0.32.0.data → snowpark_connect-0.33.0.data}/scripts/snowpark-session +0 -0
  93. {snowpark_connect-0.32.0.data → snowpark_connect-0.33.0.data}/scripts/snowpark-submit +0 -0
  94. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/WHEEL +0 -0
  95. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/licenses/LICENSE-binary +0 -0
  96. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/licenses/LICENSE.txt +0 -0
  97. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/licenses/NOTICE-binary +0 -0
  98. {snowpark_connect-0.32.0.dist-info → snowpark_connect-0.33.0.dist-info}/top_level.txt +0 -0
@@ -117,6 +117,57 @@ def _spark_to_snowflake(multipart_id: str) -> str:
117
117
  )
118
118
 
119
119
 
120
+ def _validate_table_exist_and_of_type(
121
+ snowpark_table_name: str,
122
+ session: snowpark.Session,
123
+ table_type: str,
124
+ table_schema_or_error: DataType | SnowparkSQLException,
125
+ ) -> None:
126
+ if not isinstance(table_schema_or_error, DataType):
127
+ exception = AnalysisException(
128
+ f"[TABLE_OR_VIEW_NOT_FOUND] The table or view `{snowpark_table_name}` cannot be found."
129
+ )
130
+ attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
131
+ raise exception
132
+ _validate_table_type(snowpark_table_name, session, table_type)
133
+
134
+
135
+ def _validate_table_type(
136
+ snowpark_table_name: str,
137
+ session: snowpark.Session,
138
+ table_type: str,
139
+ ) -> None:
140
+ actual_type = get_table_type(snowpark_table_name, session)
141
+ if table_type == "iceberg":
142
+ if actual_type not in ("ICEBERG", "TABLE"):
143
+ exception = AnalysisException(
144
+ f"Table {snowpark_table_name} is not an iceberg table"
145
+ )
146
+ attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
147
+ raise exception
148
+ elif table_type == "fdn":
149
+ if actual_type not in ("NORMAL", "TABLE"):
150
+ exception = AnalysisException(
151
+ f"Table {snowpark_table_name} is not a FDN table"
152
+ )
153
+ attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
154
+ raise exception
155
+ else:
156
+ raise ValueError(
157
+ f"Invalid table_type: {table_type}. Must be 'iceberg' or 'fdn'"
158
+ )
159
+
160
+
161
+ def _validate_table_does_not_exist(
162
+ snowpark_table_name: str,
163
+ table_schema_or_error: DataType | SnowparkSQLException,
164
+ ) -> None:
165
+ if isinstance(table_schema_or_error, DataType):
166
+ exception = AnalysisException(f"Table {snowpark_table_name} already exists")
167
+ attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
168
+ raise exception
169
+
170
+
120
171
  def map_write(request: proto_base.ExecutePlanRequest):
121
172
  write_op = request.plan.command.write_operation
122
173
  telemetry.report_io_write(write_op.source)
@@ -240,7 +291,6 @@ def map_write(request: proto_base.ExecutePlanRequest):
240
291
  "format_type_options": {
241
292
  "COMPRESSION": compression,
242
293
  },
243
- "overwrite": overwrite,
244
294
  }
245
295
  # Download from the base write path to ensure we fetch whatever Snowflake produced.
246
296
  # Using the base avoids coupling to exact filenames/prefixes.
@@ -347,14 +397,9 @@ def map_write(request: proto_base.ExecutePlanRequest):
347
397
  table_schema_or_error = _get_table_schema_or_error(
348
398
  snowpark_table_name, session
349
399
  )
350
- if isinstance(table_schema_or_error, DataType): # Table exists
351
- exception = AnalysisException(
352
- f"Table {snowpark_table_name} already exists"
353
- )
354
- attach_custom_error_code(
355
- exception, ErrorCodes.INVALID_OPERATION
356
- )
357
- raise exception
400
+ _validate_table_does_not_exist(
401
+ snowpark_table_name, table_schema_or_error
402
+ )
358
403
  create_iceberg_table(
359
404
  snowpark_table_name=snowpark_table_name,
360
405
  location=write_op.options.get("location", None),
@@ -373,17 +418,7 @@ def map_write(request: proto_base.ExecutePlanRequest):
373
418
  snowpark_table_name, session
374
419
  )
375
420
  if isinstance(table_schema_or_error, DataType): # Table exists
376
- if get_table_type(snowpark_table_name, session) not in (
377
- "ICEBERG",
378
- "TABLE",
379
- ):
380
- exception = AnalysisException(
381
- f"Table {snowpark_table_name} is not an iceberg table"
382
- )
383
- attach_custom_error_code(
384
- exception, ErrorCodes.INVALID_OPERATION
385
- )
386
- raise exception
421
+ _validate_table_type(snowpark_table_name, session, "iceberg")
387
422
  else:
388
423
  create_iceberg_table(
389
424
  snowpark_table_name=snowpark_table_name,
@@ -423,29 +458,25 @@ def map_write(request: proto_base.ExecutePlanRequest):
423
458
  snowpark_table_name, session
424
459
  )
425
460
  if isinstance(table_schema_or_error, DataType): # Table exists
426
- if get_table_type(snowpark_table_name, session) not in (
427
- "ICEBERG",
428
- "TABLE",
429
- ):
430
- exception = AnalysisException(
431
- f"Table {snowpark_table_name} is not an iceberg table"
432
- )
433
- attach_custom_error_code(
434
- exception, ErrorCodes.INVALID_OPERATION
435
- )
436
- raise exception
461
+ _validate_table_type(snowpark_table_name, session, "iceberg")
462
+ create_iceberg_table(
463
+ snowpark_table_name=snowpark_table_name,
464
+ location=write_op.options.get("location", None),
465
+ schema=input_df.schema,
466
+ snowpark_session=session,
467
+ mode="replace",
468
+ )
437
469
  else:
438
470
  create_iceberg_table(
439
471
  snowpark_table_name=snowpark_table_name,
440
472
  location=write_op.options.get("location", None),
441
473
  schema=input_df.schema,
442
474
  snowpark_session=session,
475
+ mode="create",
443
476
  )
444
- _validate_schema_and_get_writer(
445
- input_df, "truncate", snowpark_table_name, table_schema_or_error
446
- ).saveAsTable(
477
+ _get_writer_for_table_creation(input_df).saveAsTable(
447
478
  table_name=snowpark_table_name,
448
- mode="truncate",
479
+ mode="append",
449
480
  column_order=_column_order_for_write,
450
481
  )
451
482
  case _:
@@ -491,18 +522,9 @@ def map_write(request: proto_base.ExecutePlanRequest):
491
522
  snowpark_table_name, session
492
523
  )
493
524
  if isinstance(table_schema_or_error, DataType): # Table exists
494
- if get_table_type(snowpark_table_name, session) not in (
495
- "NORMAL",
496
- "TABLE",
497
- ):
498
- exception = AnalysisException(
499
- f"Table {snowpark_table_name} is not a FDN table"
500
- )
501
- attach_custom_error_code(
502
- exception, ErrorCodes.INVALID_OPERATION
503
- )
504
- raise exception
505
- write_mode = "truncate"
525
+ _validate_table_type(snowpark_table_name, session, "fdn")
526
+
527
+ write_mode = "overwrite"
506
528
  _validate_schema_and_get_writer(
507
529
  input_df,
508
530
  write_mode,
@@ -511,27 +533,15 @@ def map_write(request: proto_base.ExecutePlanRequest):
511
533
  ).saveAsTable(
512
534
  table_name=snowpark_table_name,
513
535
  mode=write_mode,
536
+ copy_grants=True,
514
537
  column_order=_column_order_for_write,
515
538
  )
516
539
  case "append":
517
540
  table_schema_or_error = _get_table_schema_or_error(
518
541
  snowpark_table_name, session
519
542
  )
520
- if isinstance(
521
- table_schema_or_error, DataType
522
- ) and get_table_type( # Table exists
523
- snowpark_table_name, session
524
- ) not in (
525
- "NORMAL",
526
- "TABLE",
527
- ):
528
- exception = AnalysisException(
529
- f"Table {snowpark_table_name} is not a FDN table"
530
- )
531
- attach_custom_error_code(
532
- exception, ErrorCodes.INVALID_OPERATION
533
- )
534
- raise exception
543
+ if isinstance(table_schema_or_error, DataType): # Table exists
544
+ _validate_table_type(snowpark_table_name, session, "fdn")
535
545
 
536
546
  _validate_schema_and_get_writer(
537
547
  input_df,
@@ -598,113 +608,105 @@ def map_write_v2(request: proto_base.ExecutePlanRequest):
598
608
  attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
599
609
  raise exception
600
610
 
601
- if write_op.provider.lower() == "iceberg":
602
- match write_op.mode:
603
- case commands_proto.WriteOperationV2.MODE_CREATE:
604
- table_schema_or_error = _get_table_schema_or_error(
605
- snowpark_table_name, session
606
- )
607
- if isinstance(table_schema_or_error, DataType): # Table exists
608
- exception = AnalysisException(
609
- f"Table {snowpark_table_name} already exists"
610
- )
611
- attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
612
- raise exception
611
+ is_iceberg = write_op.provider.lower() == "iceberg"
612
+ table_type = "iceberg" if is_iceberg else "fdn"
613
+
614
+ match write_op.mode:
615
+ case commands_proto.WriteOperationV2.MODE_CREATE:
616
+ table_schema_or_error = _get_table_schema_or_error(
617
+ snowpark_table_name, session
618
+ )
619
+ _validate_table_does_not_exist(snowpark_table_name, table_schema_or_error)
620
+
621
+ if is_iceberg:
613
622
  create_iceberg_table(
614
623
  snowpark_table_name=snowpark_table_name,
615
624
  location=write_op.table_properties.get("location"),
616
625
  schema=input_df.schema,
617
626
  snowpark_session=session,
618
627
  )
619
- _validate_schema_and_get_writer(
620
- input_df, "append", snowpark_table_name, table_schema_or_error
621
- ).saveAsTable(
622
- table_name=snowpark_table_name,
623
- mode="append",
624
- column_order=_column_order_for_write,
625
- )
626
- case commands_proto.WriteOperationV2.MODE_APPEND:
627
- table_schema_or_error = _get_table_schema_or_error(
628
- snowpark_table_name, session
629
- )
630
- if not isinstance(table_schema_or_error, DataType): # Table not exists
631
- exception = AnalysisException(
632
- f"[TABLE_OR_VIEW_NOT_FOUND] The table or view `{write_op.table_name}` cannot be found."
633
- )
634
- attach_custom_error_code(exception, ErrorCodes.INTERNAL_ERROR)
635
- raise exception
636
- if get_table_type(snowpark_table_name, session) not in (
637
- "ICEBERG",
638
- "TABLE",
639
- ):
640
- exception = AnalysisException(
641
- f"Table {snowpark_table_name} is not an iceberg table"
642
- )
643
- attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
644
- raise exception
645
- _validate_schema_and_get_writer(
646
- input_df, "append", snowpark_table_name, table_schema_or_error
647
- ).saveAsTable(
648
- table_name=snowpark_table_name,
649
- mode="append",
650
- column_order=_column_order_for_write,
651
- )
652
- case commands_proto.WriteOperationV2.MODE_OVERWRITE | commands_proto.WriteOperationV2.MODE_OVERWRITE_PARTITIONS:
653
- # TODO: handle the filter condition for MODE_OVERWRITE
654
- table_schema_or_error = _get_table_schema_or_error(
655
- snowpark_table_name, session
656
- )
657
- if isinstance(table_schema_or_error, DataType): # Table exists
658
- if get_table_type(snowpark_table_name, session) not in (
659
- "ICEBERG",
660
- "TABLE",
661
- ):
662
- exception = AnalysisException(
663
- f"Table {snowpark_table_name} is not an iceberg table"
664
- )
665
- attach_custom_error_code(
666
- exception, ErrorCodes.INVALID_OPERATION
667
- )
668
- raise exception
669
- else:
670
- exception = AnalysisException(
671
- f"[TABLE_OR_VIEW_NOT_FOUND] Table {snowpark_table_name} does not exist"
672
- )
673
- attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
674
- raise exception
675
- _validate_schema_and_get_writer(
676
- input_df, "truncate", snowpark_table_name, table_schema_or_error
677
- ).saveAsTable(
678
- table_name=snowpark_table_name,
679
- mode="truncate",
680
- column_order=_column_order_for_write,
628
+ _get_writer_for_table_creation(input_df).saveAsTable(
629
+ table_name=snowpark_table_name,
630
+ mode="append" if is_iceberg else "errorifexists",
631
+ column_order=_column_order_for_write,
632
+ )
633
+
634
+ case commands_proto.WriteOperationV2.MODE_APPEND:
635
+ table_schema_or_error = _get_table_schema_or_error(
636
+ snowpark_table_name, session
637
+ )
638
+ _validate_table_exist_and_of_type(
639
+ snowpark_table_name, session, table_type, table_schema_or_error
640
+ )
641
+ _validate_schema_and_get_writer(
642
+ input_df, "append", snowpark_table_name, table_schema_or_error
643
+ ).saveAsTable(
644
+ table_name=snowpark_table_name,
645
+ mode="append",
646
+ column_order=_column_order_for_write,
647
+ )
648
+
649
+ case commands_proto.WriteOperationV2.MODE_OVERWRITE | commands_proto.WriteOperationV2.MODE_OVERWRITE_PARTITIONS:
650
+ # TODO: handle the filter condition for MODE_OVERWRITE
651
+ table_schema_or_error = _get_table_schema_or_error(
652
+ snowpark_table_name, session
653
+ )
654
+ _validate_table_exist_and_of_type(
655
+ snowpark_table_name, session, table_type, table_schema_or_error
656
+ )
657
+
658
+ if is_iceberg:
659
+ create_iceberg_table(
660
+ snowpark_table_name=snowpark_table_name,
661
+ location=write_op.options.get("location", None),
662
+ schema=input_df.schema,
663
+ snowpark_session=session,
664
+ mode="replace",
681
665
  )
682
- case commands_proto.WriteOperationV2.MODE_REPLACE:
683
- table_schema_or_error = _get_table_schema_or_error(
684
- snowpark_table_name, session
666
+ writer = _get_writer_for_table_creation(input_df)
667
+ save_mode = "append"
668
+ else:
669
+ writer = _validate_schema_and_get_writer(
670
+ input_df, "overwrite", snowpark_table_name, table_schema_or_error
685
671
  )
686
- if isinstance(table_schema_or_error, DataType): # Table exists
687
- create_iceberg_table(
688
- snowpark_table_name=snowpark_table_name,
689
- location=write_op.table_properties.get("location"),
690
- schema=input_df.schema,
691
- snowpark_session=session,
692
- mode="replace",
693
- )
694
- else:
695
- exception = AnalysisException(
696
- f"Table {snowpark_table_name} does not exist"
697
- )
698
- attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
699
- raise exception
700
- _validate_schema_and_get_writer(
701
- input_df, "replace", snowpark_table_name, table_schema_or_error
702
- ).saveAsTable(
703
- table_name=snowpark_table_name,
704
- mode="append",
705
- column_order=_column_order_for_write,
672
+ save_mode = "overwrite"
673
+
674
+ writer.saveAsTable(
675
+ table_name=snowpark_table_name,
676
+ mode=save_mode,
677
+ column_order=_column_order_for_write,
678
+ )
679
+
680
+ case commands_proto.WriteOperationV2.MODE_REPLACE:
681
+ table_schema_or_error = _get_table_schema_or_error(
682
+ snowpark_table_name, session
683
+ )
684
+ _validate_table_exist_and_of_type(
685
+ snowpark_table_name, session, table_type, table_schema_or_error
686
+ )
687
+
688
+ if is_iceberg:
689
+ create_iceberg_table(
690
+ snowpark_table_name=snowpark_table_name,
691
+ location=write_op.table_properties.get("location"),
692
+ schema=input_df.schema,
693
+ snowpark_session=session,
694
+ mode="replace",
706
695
  )
707
- case commands_proto.WriteOperationV2.MODE_CREATE_OR_REPLACE:
696
+ save_mode = "append"
697
+ else:
698
+ save_mode = "overwrite"
699
+
700
+ _validate_schema_and_get_writer(
701
+ input_df, "replace", snowpark_table_name, table_schema_or_error
702
+ ).saveAsTable(
703
+ table_name=snowpark_table_name,
704
+ mode=save_mode,
705
+ column_order=_column_order_for_write,
706
+ )
707
+
708
+ case commands_proto.WriteOperationV2.MODE_CREATE_OR_REPLACE:
709
+ if is_iceberg:
708
710
  create_iceberg_table(
709
711
  snowpark_table_name=snowpark_table_name,
710
712
  location=write_op.table_properties.get("location"),
@@ -712,116 +714,24 @@ def map_write_v2(request: proto_base.ExecutePlanRequest):
712
714
  snowpark_session=session,
713
715
  mode="create_or_replace",
714
716
  )
715
- _validate_schema_and_get_writer(
716
- input_df, "create_or_replace", snowpark_table_name
717
- ).saveAsTable(
718
- table_name=snowpark_table_name,
719
- mode="append",
720
- column_order=_column_order_for_write,
721
- )
722
- case _:
723
- exception = SnowparkConnectNotImplementedError(
724
- f"Write mode {commands_proto.WriteOperationV2.Mode.Name(write_op.mode)} is not supported"
725
- )
726
- attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
727
- raise exception
728
- else:
729
- match write_op.mode:
730
- case commands_proto.WriteOperationV2.MODE_CREATE:
731
- _validate_schema_and_get_writer(
732
- input_df, "errorifexists", snowpark_table_name
733
- ).saveAsTable(
734
- table_name=snowpark_table_name,
735
- mode="errorifexists",
736
- column_order=_column_order_for_write,
737
- )
738
- case commands_proto.WriteOperationV2.MODE_APPEND:
739
- table_schema_or_error = _get_table_schema_or_error(
740
- snowpark_table_name, session
741
- )
742
- if not isinstance(table_schema_or_error, DataType): # Table not exists
743
- exception = AnalysisException(
744
- f"[TABLE_OR_VIEW_NOT_FOUND] The table or view `{write_op.table_name}` cannot be found."
745
- )
746
- attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
747
- raise exception
748
- if get_table_type(snowpark_table_name, session) not in (
749
- "NORMAL",
750
- "TABLE",
751
- ):
752
- exception = AnalysisException(
753
- f"Table {snowpark_table_name} is not a FDN table"
754
- )
755
- attach_custom_error_code(exception, ErrorCodes.INVALID_OPERATION)
756
- raise exception
757
- _validate_schema_and_get_writer(
758
- input_df, "append", snowpark_table_name, table_schema_or_error
759
- ).saveAsTable(
760
- table_name=snowpark_table_name,
761
- mode="append",
762
- column_order=_column_order_for_write,
763
- )
764
- case commands_proto.WriteOperationV2.MODE_OVERWRITE | commands_proto.WriteOperationV2.MODE_OVERWRITE_PARTITIONS:
765
- # TODO: handle the filter condition for MODE_OVERWRITE
766
- table_schema_or_error = _get_table_schema_or_error(
767
- snowpark_table_name, session
768
- )
769
- if isinstance(table_schema_or_error, DataType): # Table exists
770
- if get_table_type(snowpark_table_name, session) not in (
771
- "NORMAL",
772
- "TABLE",
773
- ):
774
- exception = AnalysisException(
775
- f"Table {snowpark_table_name} is not a FDN table"
776
- )
777
- attach_custom_error_code(
778
- exception, ErrorCodes.INVALID_OPERATION
779
- )
780
- raise exception
781
- else:
782
- exception = AnalysisException(
783
- f"[TABLE_OR_VIEW_NOT_FOUND] Table {snowpark_table_name} does not exist"
784
- )
785
- attach_custom_error_code(exception, ErrorCodes.TABLE_NOT_FOUND)
786
- raise exception
787
- _validate_schema_and_get_writer(
788
- input_df, "truncate", snowpark_table_name, table_schema_or_error
789
- ).saveAsTable(
790
- table_name=snowpark_table_name,
791
- mode="truncate",
792
- column_order=_column_order_for_write,
793
- )
794
- case commands_proto.WriteOperationV2.MODE_REPLACE:
795
- table_schema_or_error = _get_table_schema_or_error(
796
- snowpark_table_name, session
797
- )
798
- if not isinstance(table_schema_or_error, DataType): # Table not exists
799
- exception = AnalysisException(
800
- f"Table {snowpark_table_name} does not exist"
801
- )
802
- attach_custom_error_code(exception, ErrorCodes.TABLE_NOT_FOUND)
803
- raise exception
804
- _validate_schema_and_get_writer(
805
- input_df, "replace", snowpark_table_name, table_schema_or_error
806
- ).saveAsTable(
807
- table_name=snowpark_table_name,
808
- mode="overwrite",
809
- column_order=_column_order_for_write,
810
- )
811
- case commands_proto.WriteOperationV2.MODE_CREATE_OR_REPLACE:
812
- _validate_schema_and_get_writer(
813
- input_df, "create_or_replace", snowpark_table_name
814
- ).saveAsTable(
815
- table_name=snowpark_table_name,
816
- mode="overwrite",
817
- column_order=_column_order_for_write,
818
- )
819
- case _:
820
- exception = SnowparkConnectNotImplementedError(
821
- f"Write mode {commands_proto.WriteOperationV2.Mode.Name(write_op.mode)} is not supported"
822
- )
823
- attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
824
- raise exception
717
+ save_mode = "append"
718
+ else:
719
+ save_mode = "overwrite"
720
+
721
+ _validate_schema_and_get_writer(
722
+ input_df, "create_or_replace", snowpark_table_name
723
+ ).saveAsTable(
724
+ table_name=snowpark_table_name,
725
+ mode=save_mode,
726
+ column_order=_column_order_for_write,
727
+ )
728
+
729
+ case _:
730
+ exception = SnowparkConnectNotImplementedError(
731
+ f"Write mode {commands_proto.WriteOperationV2.Mode.Name(write_op.mode)} is not supported"
732
+ )
733
+ attach_custom_error_code(exception, ErrorCodes.UNSUPPORTED_OPERATION)
734
+ raise exception
825
735
 
826
736
 
827
737
  def _get_table_schema_or_error(
@@ -856,6 +766,7 @@ def _validate_schema_and_get_writer(
856
766
  if write_mode is not None and write_mode.lower() in (
857
767
  "replace",
858
768
  "create_or_replace",
769
+ "overwrite",
859
770
  ):
860
771
  return _get_writer_for_table_creation(input_df)
861
772
 
@@ -1053,14 +964,13 @@ def create_iceberg_table(
1053
964
  if config_external_volume is None or config_external_volume == ""
1054
965
  else f"EXTERNAL_VOLUME = '{config_external_volume}'"
1055
966
  )
1056
-
967
+ copy_grants = ""
1057
968
  match mode:
1058
969
  case "create":
1059
970
  create_sql = "CREATE"
1060
- case "replace":
971
+ case "replace" | "create_or_replace":
1061
972
  # There's no replace for iceberg table, so we use create or replace
1062
- create_sql = "CREATE OR REPLACE"
1063
- case "create_or_replace":
973
+ copy_grants = "COPY GRANTS"
1064
974
  create_sql = "CREATE OR REPLACE"
1065
975
  case _:
1066
976
  exception = SnowparkConnectNotImplementedError(
@@ -1072,7 +982,8 @@ def create_iceberg_table(
1072
982
  {create_sql} ICEBERG TABLE {snowpark_table_name} ({",".join(table_schema)})
1073
983
  CATALOG = 'SNOWFLAKE'
1074
984
  {external_volume}
1075
- {base_location};
985
+ {base_location}
986
+ {copy_grants};
1076
987
  """
1077
988
  snowpark_session.sql(sql).collect()
1078
989
 
@@ -1,7 +1,6 @@
1
1
  #
2
2
  # Copyright (c) 2012-2025 Snowflake Computing Inc. All rights reserved.
3
3
  #
4
- import pathlib
5
4
  import threading
6
5
  import time
7
6
 
@@ -51,11 +50,9 @@ def initialize_resources() -> None:
51
50
  """Upload Spark jar files required for creating Scala UDFs."""
52
51
  stage = session.get_session_stage()
53
52
  resource_path = stage + RESOURCE_PATH
54
- import snowflake
53
+ import snowpark_connect_deps_1
54
+ import snowpark_connect_deps_2
55
55
 
56
- pyspark_jars = (
57
- pathlib.Path(snowflake.snowpark_connect.__file__).parent / "includes/jars"
58
- )
59
56
  jar_files = [
60
57
  f"spark-sql_2.12-{SPARK_VERSION}.jar",
61
58
  f"spark-connect-client-jvm_2.12-{SPARK_VERSION}.jar",
@@ -64,14 +61,29 @@ def initialize_resources() -> None:
64
61
  "json4s-ast_2.12-3.7.0-M11.jar",
65
62
  ]
66
63
 
67
- for jar in jar_files:
68
- session.file.put(
69
- str(pyspark_jars) + "/" + jar,
70
- resource_path,
71
- auto_compress=False,
72
- overwrite=False,
73
- source_compression="NONE",
74
- )
64
+ for jar_name in jar_files:
65
+ # Try to find the JAR in package 1 first, then package 2
66
+ jar_path = None
67
+ try:
68
+ jar_path = snowpark_connect_deps_1.get_jar_path(jar_name)
69
+ except FileNotFoundError:
70
+ try:
71
+ jar_path = snowpark_connect_deps_2.get_jar_path(jar_name)
72
+ except FileNotFoundError:
73
+ raise FileNotFoundError(
74
+ f"JAR {jar_name} not found in either package"
75
+ )
76
+
77
+ try:
78
+ session.file.put(
79
+ str(jar_path),
80
+ resource_path,
81
+ auto_compress=False,
82
+ overwrite=False,
83
+ source_compression="NONE",
84
+ )
85
+ except Exception as e:
86
+ raise RuntimeError(f"Failed to upload JAR {jar_name}: {e}")
75
87
 
76
88
  start_time = time.time()
77
89