From 1f9b6e379814738103fd4fb43db760c920bdd171 Mon Sep 17 00:00:00 2001 From: Neeraj Dwivedi Date: Fri, 5 Jun 2026 09:42:27 +0530 Subject: [PATCH 1/2] first commit --- .../bq_driver/internal/odbc_conn_handle.cc | 4 ++ .../bq_driver/internal/odbc_conn_handle.h | 1 + .../odbc_driver_tests/statement_test.cc | 49 +++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.cc b/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.cc index aeea40d1ea..2827ce31da 100644 --- a/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.cc +++ b/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.cc @@ -139,6 +139,10 @@ void ConnectionHandle::SetUp(Section& dsn_section, !max_retries.empty() ? std::stoull(max_retries) : kDefaultMaxRetries; dsn_.pem_file = dsn_section["TRUSTEDCERTS"]; + std::string request_google_drive_scope = + dsn_section["REQUESTGOOGLEDRIVESCOPE"]; + dsn_.request_google_drive_scope = (request_google_drive_scope == "1" || + request_google_drive_scope == "true"); #ifdef _WIN32 auto it = dsn_section.find("USESYSTEMTRUSTSTORE"); if (it != dsn_section.end() && !it->second.empty()) { diff --git a/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h b/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h index bd026cc428..87c37e2a84 100644 --- a/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h +++ b/google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h @@ -69,6 +69,7 @@ struct Dsn { bool sessions_enabled = false; bool is_query_cache = true; bool filter_tables_on_default_dataset = false; + bool request_google_drive_scope = false; std::string session_location; std::vector connection_properties; std::uint32_t row_fetched_per_block = 100000; diff --git a/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc b/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc index e112238123..7580dd93c7 100644 --- a/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc +++ b/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc @@ -4366,4 +4366,53 @@ TEST(SQLMoreResults, ProcedureWithDescriptorAndQueryParams) { EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); } +TEST(StatementTest, VerifyGoogleDriveScope_Enabled) { + auto conn = std::make_shared(); + std::string conn_str = kDefaultConnectionString +";RequestGoogleDriveScope=1"; + EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); + + std::string table_name = + kDatasetWithTablePrefix + "ODBC_GOOGLE_DRIVE_SCOPE_TEST"; + std::string create_qry = + "CREATE OR REPLACE EXTERNAL TABLE " + kDatasetWithTablePrefix + + "ODBC_GOOGLE_DRIVE_SCOPE_TEST " + "(Student_ID INT64, " + "Major_Category STRING, " + "Year_of_Study STRING, " + "Pre_Semester_GPA FLOAT64) " + "OPTIONS (" + "format = 'GOOGLE_SHEETS', " + "uris = " + "['https://docs.google.com/spreadsheets/d/" + "19sVLFBoApdycZInuci8Hf7s12rOHKKlsdS6RmKkJdr8'], " + "skip_leading_rows = 1, " + "sheet_range = 'ai_student_impact_dataset'" + ");"; + auto status = + SQLExecDirect(conn->hstmt, (SQLCHAR*)create_qry.c_str(), SQL_NTS); + CheckError(status, "SQLExecDirect", conn); + EXPECT_EQ(status, SQL_SUCCESS); + EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); + + // verify table + EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); + std::string select_qry = "SELECT * FROM " + table_name + " LIMIT 5"; + status = SQLExecDirect(conn->hstmt, (SQLCHAR*)select_qry.c_str(), SQL_NTS); + CheckError(status, "SQLExecDirect", conn); + EXPECT_EQ(status, SQL_SUCCESS); + + status = SQLFetch(conn->hstmt); + CheckError(status, "SQLFetch", conn); + EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); + + // Cleanup. + EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); + std::string drop_qry = "DROP EXTERNAL TABLE `" + table_name + "`"; + + status = SQLExecDirect(conn->hstmt, (SQLCHAR*)drop_qry.c_str(), SQL_NTS); + + EXPECT_EQ(status, SQL_SUCCESS); + EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); +} + } // namespace google::cloud::odbc_tests From f2e7e9341efe9ae67717eedcf9d029f6c44171da Mon Sep 17 00:00:00 2001 From: Neeraj Dwivedi Date: Mon, 8 Jun 2026 16:37:52 +0530 Subject: [PATCH 2/2] second commit --- .../odbc_authentication.cc | 2 +- .../bq_client_interface/odbc_authentication.h | 1 + .../bq_client_interface/odbc_bq_client.cc | 25 ++++++++++++++++++- .../cloud/odbc/bq_driver/odbc_connection.cc | 1 + .../odbc_driver_tests/statement_test.cc | 24 +++++++++--------- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/google/cloud/odbc/bq_client_interface/odbc_authentication.cc b/google/cloud/odbc/bq_client_interface/odbc_authentication.cc index b8c1d7aa92..95caf4a875 100644 --- a/google/cloud/odbc/bq_client_interface/odbc_authentication.cc +++ b/google/cloud/odbc/bq_client_interface/odbc_authentication.cc @@ -72,7 +72,6 @@ StatusRecordOr> CreateServiceCredentials( "Service Account key file is empty or could not be read: " + credentials_file_path}; } - return ::google::cloud::MakeServiceAccountCredentials(contents, options); } @@ -194,6 +193,7 @@ StatusRecordOr GetOAuth2Token( auto self_signed_jwt_disabled = GetEnv(kSelfSignedJwtEnvVar); SetEnv(kSelfSignedJwtEnvVar, "true"); StatusOr access_token = generator->GetToken(); + std::cout << "Access Token: " << access_token->token << std::endl; SetEnv(kSelfSignedJwtEnvVar, self_signed_jwt_disabled); return StatusRecordOr::ConvertFromStatusOr(access_token); } diff --git a/google/cloud/odbc/bq_client_interface/odbc_authentication.h b/google/cloud/odbc/bq_client_interface/odbc_authentication.h index a6436e8abe..cbbd2bf9d3 100644 --- a/google/cloud/odbc/bq_client_interface/odbc_authentication.h +++ b/google/cloud/odbc/bq_client_interface/odbc_authentication.h @@ -88,6 +88,7 @@ struct Oauth { std::string kms_key_name; std::string psc; TPC tpc; + bool request_google_drive_scope = false; }; // Returns true if all required BYOID properties are set. diff --git a/google/cloud/odbc/bq_client_interface/odbc_bq_client.cc b/google/cloud/odbc/bq_client_interface/odbc_bq_client.cc index 7e42ecc02f..8a59ff3072 100644 --- a/google/cloud/odbc/bq_client_interface/odbc_bq_client.cc +++ b/google/cloud/odbc/bq_client_interface/odbc_bq_client.cc @@ -193,6 +193,27 @@ StatusRecordOr> ODBCBQClient::CreateBQClient( options.set( {"Google-Bigquery-ODBC/" + std::string(DRIVER_VERSION)}); + if(oauth.request_google_drive_scope) { + options.set( + {"https://www.googleapis.com/auth/bigquery", + "https://www.googleapis.com/auth/drive.readonly"}); + } else { + options.set( + {"https://www.googleapis.com/auth/bigquery"} + ); +} +// if (!oauth.request_google_drive_scope) { +// std::unordered_multimap custom_headers; + +// // This tells Google's API Gateway to ignore full platform credential fallback +// // and strictly evaluate the request within the narrow perimeter of BigQuery. +// custom_headers.insert({"X-Goog-Allowed-Resources", "bigquery.googleapis.com"}); + +// // Alternatively, some Google endpoints accept context downscoping headers: +// custom_headers.insert({"X-Google-Target-Scopes", "https://www.googleapis.com/auth/bigquery"}); + +// options.set(custom_headers); +// } StatusRecordOr> credentials = CreateCredentials(oauth, options); if (!credentials) { @@ -231,7 +252,9 @@ StatusRecordOr> ODBCBQClient::CreateBQClient( if (!bigquery_endpoint.empty()) { rest_options.set(bigquery_endpoint); } - + rest_options.set( + {"https://www.googleapis.com/auth/bigquery"} + ); DatasetClient dataset_client = DatasetClient(MakeDatasetConnection(rest_options)); JobClient job_client = JobClient(MakeBigQueryJobConnection(rest_options)); diff --git a/google/cloud/odbc/bq_driver/odbc_connection.cc b/google/cloud/odbc/bq_driver/odbc_connection.cc index 59ade298c0..91469f1ab7 100644 --- a/google/cloud/odbc/bq_driver/odbc_connection.cc +++ b/google/cloud/odbc/bq_driver/odbc_connection.cc @@ -90,6 +90,7 @@ Authentication CreateAuth(Dsn const& dsn) { auth.oauth.kms_key_name = dsn.kms_key_name; auth.oauth.psc = dsn.psc; auth.oauth.tpc.enable_tpc = dsn.enable_tpc; + auth.oauth.request_google_drive_scope = dsn.request_google_drive_scope; auth.oauth.tpc.universe_domain = dsn.universe_domain; return auth; } diff --git a/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc b/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc index 7580dd93c7..746e51bc9a 100644 --- a/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc +++ b/google/cloud/odbc/integration_tests/odbc_driver_tests/statement_test.cc @@ -4368,11 +4368,11 @@ TEST(SQLMoreResults, ProcedureWithDescriptorAndQueryParams) { TEST(StatementTest, VerifyGoogleDriveScope_Enabled) { auto conn = std::make_shared(); - std::string conn_str = kDefaultConnectionString +";RequestGoogleDriveScope=1"; - EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); - + std::string conn_str = kDefaultConnectionString +";RequestGoogleDriveScope=0"; + std::string table_name = - kDatasetWithTablePrefix + "ODBC_GOOGLE_DRIVE_SCOPE_TEST"; + kDatasetWithTablePrefix + "ODBC_GOOGLE_DRIVE_SCOPE_TEST"; + EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); std::string create_qry = "CREATE OR REPLACE EXTERNAL TABLE " + kDatasetWithTablePrefix + "ODBC_GOOGLE_DRIVE_SCOPE_TEST " @@ -4394,10 +4394,10 @@ TEST(StatementTest, VerifyGoogleDriveScope_Enabled) { EXPECT_EQ(status, SQL_SUCCESS); EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); - // verify table + // // verify table EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); std::string select_qry = "SELECT * FROM " + table_name + " LIMIT 5"; - status = SQLExecDirect(conn->hstmt, (SQLCHAR*)select_qry.c_str(), SQL_NTS); + status = SQLExecDirect(conn->hstmt, (SQLCHAR*)select_qry.c_str(), SQL_NTS); CheckError(status, "SQLExecDirect", conn); EXPECT_EQ(status, SQL_SUCCESS); @@ -4405,14 +4405,14 @@ TEST(StatementTest, VerifyGoogleDriveScope_Enabled) { CheckError(status, "SQLFetch", conn); EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); - // Cleanup. - EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); - std::string drop_qry = "DROP EXTERNAL TABLE `" + table_name + "`"; + // // Cleanup. + // EXPECT_EQ(Connect(conn_str, conn), SQL_SUCCESS); + // std::string drop_qry = "DROP EXTERNAL TABLE `" + table_name + "`"; - status = SQLExecDirect(conn->hstmt, (SQLCHAR*)drop_qry.c_str(), SQL_NTS); + // status = SQLExecDirect(conn->hstmt, (SQLCHAR*)drop_qry.c_str(), SQL_NTS); - EXPECT_EQ(status, SQL_SUCCESS); - EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); + // EXPECT_EQ(status, SQL_SUCCESS); + // EXPECT_EQ(Disconnect(conn), SQL_SUCCESS); } } // namespace google::cloud::odbc_tests