Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-692968: Async queries support #787

Open
wants to merge 40 commits into
base: master
Choose a base branch
from

Conversation

sfc-gh-ext-simba-nl
Copy link
Collaborator

Added snowflake_async_execute to execute async queries and snowflake_async_stmt to get previously run async queries using query id.

*
* @return sfstmt SNOWFLAKE_STMT context for async queries.
*/
SF_STMT* STDCALL snowflake_async_stmt(SF_CONNECT *sf, const char *query_id);
Copy link
Collaborator

@sfc-gh-ext-simba-hx sfc-gh-ext-simba-hx Dec 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name sounds confusing since it seems to be an equivalent of snowflake_stmt. Maybe use the similar function name as JDBC, create_resultset or to be more specific, create_async_query_result? Still return a SF_STMT instance since libsfclient doesn't have an struct specifically for result set, but would be easier to understand the functionality of the function.

lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated
char* queryStatus = snowflake_cJSON_GetStringValue(status);
ret = get_status_from_string(queryStatus);
}
else {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After seeing the logic in get_real_results I'm not quite sure whether we should set error here. Seems no data is acceptable, the error log in get_query_metadata would be the same.

lib/client.c Outdated
#ifdef _WIN32
Sleep(sleep_time);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

define this as a common function in platform.c? I think same logic being used in http_perform.c as well.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add test cases to cover typical use case, checking query status before calling any fetch/metadata API. Take JDBC doc as example, https://docs.snowflake.com/en/developer-guide/jdbc/jdbc-using#examples-of-asynchronous-queries
Add usage example in PR description as well (could be reference to test case if the code is clean enough).
Calling fetch/metadata function without checking query status also needed. Please test with queries would take some time.

@sfc-gh-ext-simba-nl sfc-gh-ext-simba-nl marked this pull request as ready for review December 10, 2024 21:16
@sfc-gh-ext-simba-nl sfc-gh-ext-simba-nl requested a review from a team as a code owner December 10, 2024 21:16
Copy link
Collaborator

@sfc-gh-jszczerbinski sfc-gh-jszczerbinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove unnecessary formatting changes. It's hard to review with so much (unnecessary?) changes.

lib/connection.c Outdated
// Remove old result URL and query code if this isn't our first rodeo
SF_FREE(result_url);
memset(query_code, 0, QUERYCODE_LEN);
data = snowflake_cJSON_GetObjectItem(*json, "data");
if (json_copy_string(&result_url, data, "getResultUrl") !=
SF_JSON_ERROR_NONE) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes? No reason to reformat.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think VS automatically did that accidentally when I wrapped it in an if clause. I'll revert these

lib/connection.c Outdated
// Error came from request up, just break
stop = SF_BOOLEAN_TRUE;
break;
GET_REQUEST_TYPE, error, SF_BOOLEAN_FALSE,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

lib/connection.c Outdated
SET_SNOWFLAKE_ERROR(error, SF_STATUS_ERROR_BAD_JSON, error_msg,
SF_SQLSTATE_UNABLE_TO_CONNECT);
break;
stop = SF_BOOLEAN_TRUE;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated
char* metadata_str = get_query_metadata(sfstmt);
if (metadata_str) {
cJSON* metadata = snowflake_cJSON_Parse(metadata_str);
cJSON* stats = snowflake_cJSON_GetObjectItem(metadata, "stats");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We assume it's an object?

lib/client.c Outdated
@@ -2073,6 +2284,13 @@ SF_STATUS STDCALL _snowflake_execute_ex(SF_STMT *sfstmt,
body = create_query_json_body(sfstmt->sql_text, sfstmt->sequence_counter,
is_string_empty(sfstmt->connection->directURL) ?
NULL : sfstmt->request_id, is_describe_only);

if (is_async_exec) {
snowflake_cJSON_AddBoolToObject(body, "asyncExec", SF_BOOLEAN_TRUE);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

snowflake_cJSON_AddBoolToObject(body, "asyncExec", is_async_exec); ?

while (strcmp(query_code, QUERY_IN_PROGRESS_CODE) == 0 ||
strcmp(query_code, QUERY_IN_PROGRESS_ASYNC_CODE) == 0) {
sf_bool isAsyncExec = SF_BOOLEAN_FALSE;
cJSON *json_body = snowflake_cJSON_Parse(body);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error handling?

tests/test_async.c Outdated Show resolved Hide resolved
tests/test_async.c Show resolved Hide resolved
tests/test_async.c Show resolved Hide resolved
tests/test_async.c Show resolved Hide resolved
include/snowflake/client.h Outdated Show resolved Hide resolved
include/snowflake/platform.h Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
lib/client.c Outdated Show resolved Hide resolved
tests/test_async.c Show resolved Hide resolved
Copy link
Collaborator

@sfc-gh-jszczerbinski sfc-gh-jszczerbinski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Still needs some work.

lib/client.c Outdated
return metadata;
}
SF_FREE(status_query);
log_info("No query metadata found. Query id: %s", sfstmt->sfqid);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

log_error? Seems this would happen if there is a bug in our code or api is misused.

lib/client.c Outdated

SF_QUERY_STATUS STDCALL snowflake_get_query_status(SF_STMT *sfstmt) {
SF_QUERY_STATUS ret = SF_QUERY_STATUS_NO_DATA;
char *metadata = get_query_metadata(sfstmt);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not free the metadata

lib/client.c Outdated
}

// Get query stats
char* metadata_str = get_query_metadata(sfstmt);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not free metadata_str?

lib/client.c Outdated
*
* The query metadata
*/
char *get_query_metadata(SF_STMT* sfstmt) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this function should return a striuct with parsed metadata instead of char array containing JSON. Consider moving parsing and validation into this function

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Especially since stringify it in this function and parse it again when it's used

lib/client.c Outdated
NULL, NULL, NULL, SF_BOOLEAN_FALSE)) {

s_resp = snowflake_cJSON_Print(resp);
log_trace("Here is JSON response:\n%s", s_resp);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please be more descriptive in logs, maybe: log_trace("GET %s returned response: %s", status_query, s_resp)

Copy link

codecov bot commented Jan 30, 2025

Codecov Report

Attention: Patch coverage is 77.77778% with 38 lines in your changes missing coverage. Please review.

Project coverage is 80.52%. Comparing base (c4b0fe2) to head (8b39c03).
Report is 10 commits behind head on master.

Files with missing lines Patch % Lines
lib/client.c 77.07% 36 Missing ⚠️
lib/http_perform.c 33.33% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #787      +/-   ##
==========================================
+ Coverage   74.36%   80.52%   +6.15%     
==========================================
  Files         105      104       -1     
  Lines        9293     9326      +33     
==========================================
+ Hits         6911     7510     +599     
+ Misses       2382     1816     -566     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -526,8 +546,10 @@ typedef struct SF_STMT {
void* multi_stmt_result_ids;
int64 multi_stmt_count;
int64 paramset_size;
sf_bool array_bind_supported;
sf_bool array_bind_supported;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix the formatting here

}
}

int sleep_time = retry_pattern[retry] * 500;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this sleep is supposed to be executed below if (retry < max_retries) to ensure it won't get out of the array bounds. Maybe let's cover the max_retries limit with a unit test.

lib/client.c Outdated
@@ -2684,6 +2907,9 @@ static SF_STATUS _snowflake_execute_with_binds_ex(SF_STMT* sfstmt,
is_string_empty(sfstmt->connection->directURL) ?
NULL : sfstmt->request_id, is_describe_only,
sfstmt->multi_stmt_count);

snowflake_cJSON_AddBoolToObject(body, "asyncExec", is_async_exec);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

formatting

lib/client.c Outdated
@@ -55,12 +57,197 @@ static SF_STATUS STDCALL
_reset_connection_parameters(SF_CONNECT *sf, cJSON *parameters,
cJSON *session_info, sf_bool do_validate);

static const char* query_status_names[] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be const itself probably, i.e.
static const char* const query_status_names[]

lib/client.c Outdated

// Get query results
char query[1024];
char* query_template = "select * from table(result_scan('%s'))";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach with use RESULT_SCAN to retrieve results has a significant flaw - the original order of the results isn't guaranteed. Probably we should use /queries/{sfqid}/result endpoint instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants