From b745b75a0c3a96c34771130205de649aef3ddb8e Mon Sep 17 00:00:00 2001 From: Matt Topol Date: Tue, 11 Aug 2026 14:05:04 -0400 Subject: [PATCH] Fix Windows builds and old-driver CI tests --- .github/workflows/_build-python-wheels.yml | 26 +++++++++++++++- .../SnowflakeDatabaseMetaDataTests.java | 31 +++++++++++-------- ...ultSetMetaDataImplStructuredTypesTest.java | 20 ++++++++++-- nodejs/tests/e2e/utils/index.ts | 16 +++++----- 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/.github/workflows/_build-python-wheels.yml b/.github/workflows/_build-python-wheels.yml index 8e1ac63b99..0e040525dc 100644 --- a/.github/workflows/_build-python-wheels.yml +++ b/.github/workflows/_build-python-wheels.yml @@ -81,7 +81,7 @@ jobs: "os": "windows-latest", "container": "", "cargo_lib": "sf_core_python.dll", - "cargo_extra_args": "--features vendored-openssl --config profile.release.opt-level=2 --config profile.release.strip=false", + "cargo_extra_args": "--config profile.release.opt-level=2 --config profile.release.strip=false", "wheel_method": "cibuildwheel", "cibw_arch": "win_amd64", "artifact_id": "win_amd64", @@ -270,6 +270,22 @@ jobs: uv python install "$v" done + # Use the same vcpkg-provided OpenSSL setup as the Windows ARM64 build. + # Building vendored OpenSSL here delegates to the runner's MSYS2 Perl, + # whose incomplete core-module installation is not suitable for OpenSSL's + # Configure script (for example, Locale::Maketext::Simple may be absent). + - name: Setup OpenSSL (Windows x86_64) + if: runner.os == 'Windows' + uses: ./.github/actions/setup-windows-openssl + with: + arch: x86_64 + + - name: Setup MSVC environment (Windows x86_64) + if: runner.os == 'Windows' + uses: ./.github/actions/setup-msvc + with: + arch: x64 + # ── python_bridge build: Linux (Docker + manylinux for glibc compat) ── # Cannot use job-level container: because cibuildwheel needs Docker. # Instead, build python_bridge via docker run with the manylinux image. @@ -487,6 +503,8 @@ jobs: CIBW_ENVIRONMENT_WINDOWS: >- SKIP_CORE_BUILD=true SKIP_PROTO_GENERATION=true + DISTUTILS_USE_SDK=1 + MSSdk=1 CIBW_ENVIRONMENT_MACOS: >- SKIP_CORE_BUILD=true SKIP_PROTO_GENERATION=true @@ -646,6 +664,12 @@ jobs: working-directory: ./python shell: cmd run: uv run --python ${{ matrix.py }} --with hatch --with cython --with setuptools --with "virtualenv<21.0.0" hatch build + env: + # setup-msvc already exported a complete ARM64 compiler environment. + # Re-running vcvarsall from setuptools appends that environment to an + # already-long PATH and can exceed cmd.exe's input-line limit. + DISTUTILS_USE_SDK: "1" + MSSdk: "1" - name: Inspect wheel working-directory: ./python diff --git a/jdbc/src/test/java/net/snowflake/client/api/metadata/SnowflakeDatabaseMetaDataTests.java b/jdbc/src/test/java/net/snowflake/client/api/metadata/SnowflakeDatabaseMetaDataTests.java index e597f571aa..34ac5d82b4 100644 --- a/jdbc/src/test/java/net/snowflake/client/api/metadata/SnowflakeDatabaseMetaDataTests.java +++ b/jdbc/src/test/java/net/snowflake/client/api/metadata/SnowflakeDatabaseMetaDataTests.java @@ -1284,19 +1284,24 @@ void shouldReturnTablePrivilegesForGetTablePrivileges() throws Exception { assertMetadataColumn(rsMeta, 6, "PRIVILEGE"); assertMetadataColumn(rsMeta, 7, "IS_GRANTABLE"); - assertTrue(resultSet.next()); - assertEquals(currentDatabase, resultSet.getString("TABLE_CAT")); - assertEquals(currentSchema, resultSet.getString("TABLE_SCHEM")); - assertEquals(targetTable, resultSet.getString("TABLE_NAME")); - String grantor = resultSet.getString("GRANTOR"); - assertNotNull(grantor); - assertFalse(grantor.isEmpty()); - String grantee = resultSet.getString("GRANTEE"); - assertNotNull(grantee); - assertFalse(grantee.isEmpty()); - assertEquals("OWNERSHIP", resultSet.getString("PRIVILEGE")); - assertEquals("YES", resultSet.getString("IS_GRANTABLE")); - assertFalse(resultSet.next()); + boolean ownershipFound = false; + while (resultSet.next()) { + assertEquals(currentDatabase, resultSet.getString("TABLE_CAT")); + assertEquals(currentSchema, resultSet.getString("TABLE_SCHEM")); + assertEquals(targetTable, resultSet.getString("TABLE_NAME")); + String grantor = resultSet.getString("GRANTOR"); + assertNotNull(grantor); + assertFalse(grantor.isEmpty()); + String grantee = resultSet.getString("GRANTEE"); + assertNotNull(grantee); + assertFalse(grantee.isEmpty()); + + if ("OWNERSHIP".equals(resultSet.getString("PRIVILEGE"))) { + assertEquals("YES", resultSet.getString("IS_GRANTABLE")); + ownershipFound = true; + } + } + assertTrue(ownershipFound, "expected an OWNERSHIP privilege row"); } try (ResultSet resultSet = diff --git a/jdbc/src/test/java/net/snowflake/client/api/resultset/metadata/SnowflakeResultSetMetaDataImplStructuredTypesTest.java b/jdbc/src/test/java/net/snowflake/client/api/resultset/metadata/SnowflakeResultSetMetaDataImplStructuredTypesTest.java index d2031daf91..4f4536d004 100644 --- a/jdbc/src/test/java/net/snowflake/client/api/resultset/metadata/SnowflakeResultSetMetaDataImplStructuredTypesTest.java +++ b/jdbc/src/test/java/net/snowflake/client/api/resultset/metadata/SnowflakeResultSetMetaDataImplStructuredTypesTest.java @@ -7,6 +7,7 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSetMetaData; +import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.List; @@ -25,12 +26,27 @@ class SnowflakeResultSetMetaDataImplStructuredTypesTest extends SnowflakeIntegra private Connection openStructuredTypesConnection() throws Exception { Connection conn = openConnection(); try (Statement stmt = conn.createStatement()) { - stmt.execute("ALTER SESSION SET ENABLE_STRUCTURED_TYPES_IN_CLIENT_RESPONSE = TRUE"); - stmt.execute("ALTER SESSION SET IGNORE_CLIENT_VESRION_IN_STRUCTURED_TYPES_RESPONSE = TRUE"); + setSessionParameterIfSupported(stmt, "ENABLE_STRUCTURED_TYPES_IN_CLIENT_RESPONSE"); + setSessionParameterIfSupported(stmt, "IGNORE_CLIENT_VESRION_IN_STRUCTURED_TYPES_RESPONSE"); } return conn; } + private static void setSessionParameterIfSupported(Statement stmt, String parameter) + throws SQLException { + try { + stmt.execute("ALTER SESSION SET " + parameter + " = TRUE"); + } catch (SQLException exception) { + // These feature gates are absent after structured types become enabled by + // default. Preserve failures other than the expected retired-parameter + // response so connection and query regressions remain visible. + String message = exception.getMessage(); + if (message == null || !message.contains("invalid parameter '" + parameter + "'")) { + throw exception; + } + } + } + @Test @SkipNewDriver("not yet implemented - structured types field metadata") void shouldDescribeStructuredObjectFieldMetadata() throws Exception { diff --git a/nodejs/tests/e2e/utils/index.ts b/nodejs/tests/e2e/utils/index.ts index b9726f55d1..799f697186 100644 --- a/nodejs/tests/e2e/utils/index.ts +++ b/nodejs/tests/e2e/utils/index.ts @@ -6,18 +6,20 @@ import type { StatementOption, } from 'snowflake-sdk'; import oldSnowflakeSDK from 'snowflake-sdk'; -// TODO: -// Ensure tests run against the built package to catch any missing files in the build output. -// Namespace import (not default): src/index.js only has named exports. A default import -// works under Vitest interop but fails under plain Node/tsx with -// "does not provide an export named 'default'". -import * as newSnowflakeSDK from '../../../src/index.js'; import getTestParameter from './getTestParameter'; export function isRunningForOldDriver() { return !!process.env.SNOWFLAKE_NODEJS_E2E_USE_OLD_DRIVER; } +// Importing src/index.js loads the platform-specific native core immediately. +// Keep that import out of the old-driver project: its CI job intentionally does +// not build the new core and should exercise only the published legacy SDK. +// TODO: Import the built package in new-driver tests to catch missing output files. +const newSnowflakeSDK = isRunningForOldDriver() + ? undefined + : ((await import('../../../src/index.js')) as unknown as typeof oldSnowflakeSDK); + export function getSnowflakeSDK() { if (isRunningForOldDriver()) { return oldSnowflakeSDK; @@ -25,7 +27,7 @@ export function getSnowflakeSDK() { // TODO: // temporary using `as SnowflakeSDK` to satisfy the type checker until // new SDK is fully implemented - return newSnowflakeSDK as typeof oldSnowflakeSDK; + return newSnowflakeSDK!; } }