Skip to content

Commit 84238be

Browse files
[SNOW-2039995] Implement application path override in CLIENT_ENVIRONMENT (#983)
1 parent 506b520 commit 84238be

File tree

6 files changed

+78
-4
lines changed

6 files changed

+78
-4
lines changed

include/snowflake/client.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,8 @@ typedef enum SF_ATTRIBUTE {
348348
SF_CON_WIF_PROVIDER,
349349
SF_CON_WIF_TOKEN,
350350
SF_CON_WIF_AZURE_RESOURCE,
351-
SF_CON_WORKLOAD_IDENTITY_IMPERSONATION_PATH
351+
SF_CON_WORKLOAD_IDENTITY_IMPERSONATION_PATH,
352+
SF_CON_APPLICATION_PATH
352353
} SF_ATTRIBUTE;
353354

354355
/**
@@ -462,6 +463,9 @@ typedef struct SF_CONNECT {
462463
// Partner application name
463464
char * application;
464465

466+
// Override for APPLICATION_PATH in CLIENT_ENVIRONMENT
467+
char * application_path;
468+
465469
// Proxy
466470
char * proxy;
467471
char * no_proxy;

lib/client.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@ SF_STATUS STDCALL snowflake_term(SF_CONNECT *sf) {
12361236
SF_FREE(sf->application_name);
12371237
SF_FREE(sf->application_version);
12381238
SF_FREE(sf->application);
1239+
SF_FREE(sf->application_path);
12391240
SF_FREE(sf->timezone);
12401241
SF_FREE(sf->service_name);
12411242
SF_FREE(sf->query_result_format);
@@ -1640,6 +1641,9 @@ SF_STATUS STDCALL snowflake_set_attribute(
16401641
case SF_CON_APPLICATION:
16411642
alloc_buffer_and_copy(&sf->application, value);
16421643
break;
1644+
case SF_CON_APPLICATION_PATH:
1645+
alloc_buffer_and_copy(&sf->application_path, value);
1646+
break;
16431647
case SF_CON_AUTHENTICATOR:
16441648
alloc_buffer_and_copy(&sf->authenticator, value);
16451649
break;
@@ -1908,6 +1912,9 @@ SF_STATUS STDCALL snowflake_get_attribute(
19081912
case SF_CON_APPLICATION:
19091913
*value = sf->application;
19101914
break;
1915+
case SF_CON_APPLICATION_PATH:
1916+
*value = sf->application_path;
1917+
break;
19111918
case SF_CON_AUTHENTICATOR:
19121919
*value = sf->authenticator;
19131920
break;

lib/connection.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ cJSON *STDCALL create_auth_json_body(SF_CONNECT *sf,
4343
strcpy(app_path, "/app/path");
4444
#else
4545
sf_os_version(os_version, sizeof(os_version));
46-
sf_get_callers_executable_path(app_path, sizeof(app_path));
46+
// Use application_path override if provided, otherwise detect automatically
47+
if (sf->application_path && sf->application_path[0] != '\0') {
48+
sf_strncpy(app_path, sizeof(app_path), sf->application_path, sizeof(app_path) - 1);
49+
app_path[sizeof(app_path) - 1] = '\0';
50+
} else {
51+
sf_get_callers_executable_path(app_path, sizeof(app_path));
52+
}
4753
#endif
4854
snowflake_cJSON_AddStringToObject(client_env, "OS_VERSION", os_version);
4955
snowflake_cJSON_AddStringToObject(client_env, "APPLICATION_PATH", app_path);

tests/test_multiple_statements.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ void test_multi_stmt_with_large_result(void **unused)
177177
status = snowflake_query(sfstmt,
178178
"create or replace temporary table test_multi_large(c1 number, c2 number);\n"
179179
"insert into test_multi_large select seq4(), TO_VARCHAR(seq4()) from table(generator(rowcount => 100000));\n"
180-
"select * from test_multi_large",
180+
"select * from test_multi_large order by c1",
181181
0);
182182
if (status != SF_STATUS_SUCCESS) {
183183
dump_error(&(sfstmt->error));
@@ -335,7 +335,7 @@ void test_multi_stmt_arrow_format(void **unused)
335335
status = snowflake_query(sfstmt,
336336
"create or replace temporary table test_multi_large(c1 number, c2 number);\n"
337337
"insert into test_multi_large select seq4(), TO_VARCHAR(seq4()) from table(generator(rowcount => 100000));\n"
338-
"select * from test_multi_large",
338+
"select * from test_multi_large order by c1",
339339
0);
340340
if (status != SF_STATUS_SUCCESS) {
341341
dump_error(&(sfstmt->error));

tests/test_unit_mfa_auth.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
void test_json_data_in_MFA_Auth(void **unused)
1010
{
11+
SF_UNUSED(unused);
1112
SF_CONNECT* sf = (SF_CONNECT*)SF_CALLOC(1, sizeof(SF_CONNECT));
1213
sf->account = "testaccount";
1314
sf->host = "testaccount.snowflakecomputing.com";
@@ -62,11 +63,66 @@ void test_json_data_in_MFA_Auth(void **unused)
6263
SF_FREE(sf);
6364
}
6465

66+
/**
67+
* Test that application_path override is used in CLIENT_ENVIRONMENT.
68+
*/
69+
void test_application_path_override(void **unused)
70+
{
71+
SF_UNUSED(unused);
72+
SF_CONNECT* sf = (SF_CONNECT*)SF_CALLOC(1, sizeof(SF_CONNECT));
73+
sf->account = "testaccount";
74+
sf->host = "testaccount.snowflakecomputing.com";
75+
sf->user = "testuser";
76+
sf->password = "testpassword";
77+
sf->authenticator = SF_AUTHENTICATOR_DEFAULT;
78+
sf->application_name = SF_API_NAME;
79+
sf->application_version = SF_API_VERSION;
80+
81+
// Test 1: Without override, APPLICATION_PATH should be auto-detected
82+
// (In mock mode it will be "/app/path")
83+
cJSON *body = create_auth_json_body(
84+
sf,
85+
sf->application,
86+
sf->application_name,
87+
sf->application_version,
88+
sf->timezone,
89+
sf->autocommit);
90+
cJSON* data = snowflake_cJSON_GetObjectItem(body, "data");
91+
cJSON* client_env = snowflake_cJSON_GetObjectItem(data, "CLIENT_ENVIRONMENT");
92+
cJSON* app_path = snowflake_cJSON_GetObjectItem(client_env, "APPLICATION_PATH");
93+
94+
assert_non_null(app_path);
95+
// In non-mock mode this would be the executable path, in mock mode it's "/app/path"
96+
assert_non_null(snowflake_cJSON_GetStringValue(app_path));
97+
snowflake_cJSON_Delete(body);
98+
99+
// Test 2: With override, APPLICATION_PATH should use the custom value
100+
sf->application_path = "/custom/path/to/my_script.php";
101+
102+
body = create_auth_json_body(
103+
sf,
104+
sf->application,
105+
sf->application_name,
106+
sf->application_version,
107+
sf->timezone,
108+
sf->autocommit);
109+
data = snowflake_cJSON_GetObjectItem(body, "data");
110+
client_env = snowflake_cJSON_GetObjectItem(data, "CLIENT_ENVIRONMENT");
111+
app_path = snowflake_cJSON_GetObjectItem(client_env, "APPLICATION_PATH");
112+
113+
assert_non_null(app_path);
114+
assert_string_equal(snowflake_cJSON_GetStringValue(app_path), "/custom/path/to/my_script.php");
115+
snowflake_cJSON_Delete(body);
116+
117+
SF_FREE(sf);
118+
}
119+
65120
int main(void)
66121
{
67122
initialize_test(SF_BOOLEAN_FALSE);
68123
const struct CMUnitTest tests[] = {
69124
cmocka_unit_test(test_json_data_in_MFA_Auth),
125+
cmocka_unit_test(test_application_path_override),
70126
};
71127
int ret = cmocka_run_group_tests(tests, NULL, NULL);
72128
snowflake_global_term();

tests/test_unit_set_get_attributes.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ std::vector<sf_string_attributes> strAttributes = {
3030
{ SF_CON_TIMEZONE, "test_timezone" },
3131
{ SF_CON_SERVICE_NAME, "test_service_name" },
3232
{ SF_CON_APPLICATION, "test_application" },
33+
{ SF_CON_APPLICATION_PATH, "/path/to/my/script.php" },
3334
{ SF_CON_PRIV_KEY_FILE, "test_priv_key_file" },
3435
{ SF_CON_PRIV_KEY_FILE_PWD, "test_priv_key_file_pwd" },
3536
{ SF_CON_PROXY, "test_proxy" },

0 commit comments

Comments
 (0)