Skip to content

Commit 6027c11

Browse files
feat(csharp/src/Drivers/BigQuery): support evaluation kind and statement type setting (#2698)
Support evaluation kind and statement type setting for GBQ driver, and improve code at BigQueryStatement.cs.
1 parent 2ea2fcb commit 6027c11

File tree

8 files changed

+104
-24
lines changed

8 files changed

+104
-24
lines changed

csharp/src/Drivers/BigQuery/BigQueryConnection.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,10 @@ private IReadOnlyDictionary<string, string> ParseOptions()
10581058
BigQueryParameters.LargeDecimalsAsString,
10591059
BigQueryParameters.LargeResultsDestinationTable,
10601060
BigQueryParameters.GetQueryResultsOptionsTimeout,
1061-
BigQueryParameters.MaxFetchConcurrency
1061+
BigQueryParameters.MaxFetchConcurrency,
1062+
BigQueryParameters.StatementType,
1063+
BigQueryParameters.StatementIndex,
1064+
BigQueryParameters.EvaluationKind
10621065
};
10631066

10641067
foreach (string key in statementOptions)

csharp/src/Drivers/BigQuery/BigQueryParameters.cs

+3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ public class BigQueryParameters
3939
public const string GetQueryResultsOptionsTimeout = "adbc.bigquery.get_query_results_options.timeout";
4040
public const string MaxFetchConcurrency = "adbc.bigquery.max_fetch_concurrency";
4141
public const string IncludePublicProjectId = "adbc.bigquery.include_public_project_id";
42+
public const string StatementType = "adbc.bigquery.multiple_statement.statement_type";
43+
public const string StatementIndex = "adbc.bigquery.multiple_statement.statement_index";
44+
public const string EvaluationKind = "adbc.bigquery.multiple_statement.evaluation_kind";
4245
}
4346

4447
/// <summary>

csharp/src/Drivers/BigQuery/BigQueryStatement.cs

+38-23
Original file line numberDiff line numberDiff line change
@@ -51,52 +51,71 @@ public BigQueryStatement(BigQueryClient client, GoogleCredential credential)
5151

5252
public override QueryResult ExecuteQuery()
5353
{
54+
// Create job
5455
QueryOptions queryOptions = ValidateOptions();
55-
5656
BigQueryJob job = this.client.CreateQueryJob(SqlQuery, null, queryOptions);
5757

58+
// Get results
5859
GetQueryResultsOptions getQueryResultsOptions = new GetQueryResultsOptions();
59-
6060
if (this.Options?.TryGetValue(BigQueryParameters.GetQueryResultsOptionsTimeout, out string? timeoutSeconds) == true &&
6161
int.TryParse(timeoutSeconds, out int seconds) &&
6262
seconds >= 0)
6363
{
6464
getQueryResultsOptions.Timeout = TimeSpan.FromSeconds(seconds);
6565
}
66-
6766
BigQueryResults results = job.GetQueryResults(getQueryResultsOptions);
6867

69-
BigQueryReadClientBuilder readClientBuilder = new BigQueryReadClientBuilder();
70-
readClientBuilder.Credential = this.credential;
71-
BigQueryReadClient readClient = readClientBuilder.Build();
72-
68+
// For multi-statement queries, the results.TableReference is null
7369
if (results.TableReference == null)
7470
{
75-
// To get the results of all statements in a multi-statement query, enumerate the child jobs and call jobs.getQueryResults on each of them.
76-
// Related public docs: https://cloud.google.com/bigquery/docs/multi-statement-queries#get_all_executed_statements
71+
string statementType = string.Empty;
72+
if (this.Options?.TryGetValue(BigQueryParameters.StatementType, out string? statementTypeString) == true)
73+
{
74+
statementType = statementTypeString;
75+
}
76+
int statementIndex = 1;
77+
if (this.Options?.TryGetValue(BigQueryParameters.StatementIndex, out string? statementIndexString) == true &&
78+
int.TryParse(statementIndexString, out int statementIndexInt) &&
79+
statementIndexInt > 0)
80+
{
81+
statementIndex = statementIndexInt;
82+
}
83+
string evaluationKind = string.Empty;
84+
if (this.Options?.TryGetValue(BigQueryParameters.EvaluationKind, out string? evaluationKindString) == true)
85+
{
86+
evaluationKind = evaluationKindString;
87+
}
88+
89+
// To get the results of all statements in a multi-statement query, enumerate the child jobs. Related public docs: https://cloud.google.com/bigquery/docs/multi-statement-queries#get_all_executed_statements.
90+
// Can filter by StatementType and EvaluationKind. Related public docs: https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#jobstatistics2, https://cloud.google.com/bigquery/docs/reference/rest/v2/Job#evaluationkind
7791
ListJobsOptions listJobsOptions = new ListJobsOptions();
7892
listJobsOptions.ParentJobId = results.JobReference.JobId;
79-
PagedEnumerable<JobList, BigQueryJob> joblist = client.ListJobs(listJobsOptions);
80-
BigQueryJob firstQueryJob = new BigQueryJob(client, job.Resource);
81-
foreach (BigQueryJob childJob in joblist)
93+
var joblist = client.ListJobs(listJobsOptions)
94+
.Select(job => client.GetJob(job.Reference))
95+
.Where(job => string.IsNullOrEmpty(evaluationKind) || job.Statistics.ScriptStatistics.EvaluationKind.Equals(evaluationKind, StringComparison.OrdinalIgnoreCase))
96+
.Where(job => string.IsNullOrEmpty(statementType) || job.Statistics.Query.StatementType.Equals(statementType,StringComparison.OrdinalIgnoreCase))
97+
.OrderBy(job => job.Resource.Statistics.CreationTime)
98+
.ToList();
99+
100+
if (joblist.Count > 0)
82101
{
83-
var tempJob = client.GetJob(childJob.Reference);
84-
var query = tempJob.Resource?.Configuration?.Query;
85-
if (query != null && query.DestinationTable != null && query.DestinationTable.ProjectId != null && query.DestinationTable.DatasetId != null && query.DestinationTable.TableId != null)
102+
if (statementIndex < 1 || statementIndex > joblist.Count)
86103
{
87-
firstQueryJob = tempJob;
104+
throw new ArgumentOutOfRangeException($"The specified index {statementIndex} is out of range. There are {joblist.Count} jobs available.");
88105
}
106+
results = joblist[statementIndex - 1].GetQueryResults(getQueryResultsOptions);
89107
}
90-
results = firstQueryJob.GetQueryResults();
91108
}
92-
93109
if (results.TableReference == null)
94110
{
95111
throw new AdbcException("There is no query statement");
96112
}
97113

114+
// BigQuery Read Client for streaming
115+
BigQueryReadClientBuilder readClientBuilder = new BigQueryReadClientBuilder();
116+
readClientBuilder.Credential = this.credential;
117+
BigQueryReadClient readClient = readClientBuilder.Build();
98118
string table = $"projects/{results.TableReference.ProjectId}/datasets/{results.TableReference.DatasetId}/tables/{results.TableReference.TableId}";
99-
100119
int maxStreamCount = 1;
101120
if (this.Options?.TryGetValue(BigQueryParameters.MaxFetchConcurrency, out string? maxStreamCountString) == true)
102121
{
@@ -110,16 +129,12 @@ public override QueryResult ExecuteQuery()
110129
}
111130
ReadSession rs = new ReadSession { Table = table, DataFormat = DataFormat.Arrow };
112131
ReadSession rrs = readClient.CreateReadSession("projects/" + results.TableReference.ProjectId, rs, maxStreamCount);
113-
114132
long totalRows = results.TotalRows == null ? -1L : (long)results.TotalRows.Value;
115-
116133
var readers = rrs.Streams
117134
.Select(s => ReadChunk(readClient, s.Name))
118135
.Where(chunk => chunk != null)
119136
.Cast<IArrowReader>();
120-
121137
IArrowArrayStream stream = new MultiArrowReader(TranslateSchema(results.Schema), readers);
122-
123138
return new QueryResult(totalRows, stream);
124139
}
125140

csharp/src/Drivers/BigQuery/readme.md

+9
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ https://cloud.google.com/dotnet/docs/reference/Google.Cloud.BigQuery.V2/latest/G
6363
**adbc.bigquery.max_fetch_concurrency**<br>
6464
&nbsp;&nbsp;&nbsp;&nbsp;Optional. Sets the [maxStreamCount](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.BigQuery.Storage.V1/latest/Google.Cloud.BigQuery.Storage.V1.BigQueryReadClient#Google_Cloud_BigQuery_Storage_V1_BigQueryReadClient_CreateReadSession_System_String_Google_Cloud_BigQuery_Storage_V1_ReadSession_System_Int32_Google_Api_Gax_Grpc_CallSettings_) for the CreateReadSession method. If not set, defaults to 1.
6565

66+
**adbc.bigquery.multiple_statement.statement_type**<br>
67+
&nbsp;&nbsp;&nbsp;&nbsp;Optional. When executing multiple statements, limit the type of statement returned. If not set, all types of statements are returned.
68+
69+
**adbc.bigquery.multiple_statement.statement_index**<br>
70+
&nbsp;&nbsp;&nbsp;&nbsp;Optional. When executing multiple statements, specify the result of the statement to be returned (Minimum value is 1). If not set, the result of the first statement is returned.
71+
72+
**adbc.bigquery.multiple_statement.evaluation_kind**<br>
73+
&nbsp;&nbsp;&nbsp;&nbsp;Optional. When executing multiple statements, limit the evaluation kind returned. If not set, all evaluation kinds are returned.
74+
6675
**adbc.bigquery.include_constraints_getobjects**<br>
6776
&nbsp;&nbsp;&nbsp;&nbsp;Optional. Some callers do not need the constraint details when they get the table information and can improve the speed of obtaining the results. Setting this value to `"false"` will not include the constraint details. The default value is `"true"`.
6877

csharp/test/Drivers/BigQuery/BigQueryTestConfiguration.cs

+9
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ public BigQueryTestEnvironment()
9797
[JsonPropertyName("maxStreamCount")]
9898
public int? MaxStreamCount { get; set; }
9999

100+
[JsonPropertyName("statementType")]
101+
public string StatementType { get; set; } = string.Empty;
102+
103+
[JsonPropertyName("statementIndex")]
104+
public int? StatementIndex { get; set; }
105+
106+
[JsonPropertyName("evaluationKind")]
107+
public string EvaluationKind { get; set; } = string.Empty;
108+
100109
/// <summary>
101110
/// How structs should be handled by the ADO.NET client for this environment.
102111
/// </summary>

csharp/test/Drivers/BigQuery/BigQueryTestingUtils.cs

+15
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ internal static Dictionary<string, string> GetBigQueryParameters(BigQueryTestEnv
115115
parameters.Add(BigQueryParameters.MaxFetchConcurrency, testEnvironment.MaxStreamCount.Value.ToString());
116116
}
117117

118+
if (!string.IsNullOrEmpty(testEnvironment.StatementType))
119+
{
120+
parameters.Add(BigQueryParameters.StatementType, testEnvironment.StatementType);
121+
}
122+
123+
if (testEnvironment.StatementIndex.HasValue)
124+
{
125+
parameters.Add(BigQueryParameters.StatementIndex, testEnvironment.StatementIndex.Value.ToString());
126+
}
127+
128+
if (!string.IsNullOrEmpty(testEnvironment.EvaluationKind))
129+
{
130+
parameters.Add(BigQueryParameters.EvaluationKind, testEnvironment.EvaluationKind);
131+
}
132+
118133
return parameters;
119134
}
120135

csharp/test/Drivers/BigQuery/DriverTests.cs

+23
Original file line numberDiff line numberDiff line change
@@ -346,5 +346,28 @@ public void QueryTimeoutTest()
346346
}
347347
}
348348
}
349+
350+
/// <summary>
351+
/// Validates if the driver can connect to a live server and
352+
/// parse the results of multi-statements.
353+
/// </summary>
354+
[SkippableFact, Order(9)]
355+
public void CanExecuteMultiStatementQuery()
356+
{
357+
foreach (BigQueryTestEnvironment environment in _environments)
358+
{
359+
AdbcConnection adbcConnection = GetAdbcConnection(environment.Name);
360+
AdbcStatement statement = adbcConnection.CreateStatement();
361+
string query1 = "SELECT * FROM bigquery-public-data.covid19_ecdc.covid_19_geographic_distribution_worldwide";
362+
string query2 = "SELECT " +
363+
"CAST(1.7976931348623157e+308 as FLOAT64) as number, " +
364+
"PARSE_NUMERIC(\"9.99999999999999999999999999999999E+28\") as decimal, " +
365+
"PARSE_BIGNUMERIC(\"5.7896044618658097711785492504343953926634992332820282019728792003956564819968E+37\") as big_decimal";
366+
string combinedQuery = query1 + ";" + query2 + ";";
367+
statement.SqlQuery = combinedQuery;
368+
QueryResult queryResult = statement.ExecuteQuery();
369+
Tests.DriverTests.CanExecuteQuery(queryResult, 61900, environment.Name);
370+
}
371+
}
349372
}
350373
}

csharp/test/Drivers/BigQuery/readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ The following values can be setup in the configuration
4747
- **scopes** - Comma separated list (string) of scopes applied during the test.
4848
- **queryTimeout** - The timeout (in seconds) for a query. Similar to a CommandTimeout.
4949
- **maxStreamCount** - The max stream count.
50+
- **statementType** - When executing multiple statements, limit the type of statement returned.
51+
- **statementIndex** - When executing multiple statements, specify the result of the statement to be returned.
52+
- **evaluationKind** - When executing multiple statements, limit the evaluation kind returned.
5053
- **includeTableConstraints** - Whether to include table constraints in the GetObjects query.
5154
- **largeResultsDestinationTable** - Sets the [DestinationTable](https://cloud.google.com/dotnet/docs/reference/Google.Cloud.BigQuery.V2/latest/Google.Cloud.BigQuery.V2.QueryOptions#Google_Cloud_BigQuery_V2_QueryOptions_DestinationTable) value of the QueryOptions if configured. Expects the format to be `{projectId}.{datasetId}.{tableId}` to set the corresponding values in the [TableReference](https://github.com/googleapis/google-api-dotnet-client/blob/6c415c73788b848711e47c6dd33c2f93c76faf97/Src/Generated/Google.Apis.Bigquery.v2/Google.Apis.Bigquery.v2.cs#L9348) class.
5255
- **allowLargeResults** - Whether to allow large results .

0 commit comments

Comments
 (0)