Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions google/cloud/odbc/bq_driver/internal/driver_adv_opt_form.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ std::string AdvanceOptions::private_service_connect_uris_;
std::string AdvanceOptions::enable_gcd_;
std::string AdvanceOptions::universe_domain_;
std::string AdvanceOptions::maximum_bytes_billed_;
std::string AdvanceOptions::allowed_projects_;

std::string const kLanguageDialect = "SQLDialect";
std::string const kLargeResultsDatasetId = "LargeResultsDatasetId";
Expand All @@ -90,6 +91,7 @@ std::string const kPrivateServiceConnectUris = "PrivateServiceConnectUris";
std::string const kEnableGcd = "EnableGCD";
std::string const kUniverseDomain = "UniverseDomain";
std::string const kMaximumBytesBilled = "MaximumBytesBilled";
std::string const kAllowedProjects = "AllowedProjects";

// Control dimensions and positions
int const kHeight = 20;
Expand Down Expand Up @@ -383,11 +385,11 @@ void AdvanceOptions::CreateAdditionalControls(HFONT h_font) {

// max retries
HWND h_max_retries_label =
CreateLabel(adv_hwnd, "Max Retries:", kXAxis, kYAxis + 465, kWidth * 7,
CreateLabel(adv_hwnd, "Max Retries:", kXAxis, kYAxis + 460, kWidth * 7,
kHeight, WS_VISIBLE | SS_LEFT);
SendMessage(h_max_retries_label, WM_SETFONT, (WPARAM)h_font, TRUE);
HWND h_max_retries_edit =
CreateEditBox(adv_hwnd, kinputComboBoxXAxis, kYAxis + 465, kEditBoxWidth,
CreateEditBox(adv_hwnd, kinputComboBoxXAxis, kYAxis + 460, kEditBoxWidth,
kEditBoxHeight, kIdcMaxRetriesEdit);
SendMessage(h_max_retries_edit, WM_SETFONT, (WPARAM)h_font, TRUE);
SetWindowSubclass(GetDlgItem(adv_hwnd, kIdcMaxRetriesEdit), InputSubclassProc,
Expand All @@ -400,10 +402,10 @@ void AdvanceOptions::CreateAdditionalControls(HFONT h_font) {
// maximum bytes billed
HWND h_maximum_bytes_billed_label =
CreateLabel(adv_hwnd, "Maximum bytes billed (bytes):", kXAxis,
kYAxis + 490, kWidth * 4 + 25, kHeight, WS_VISIBLE | SS_LEFT);
kYAxis + 485, kWidth * 4 + 25, kHeight, WS_VISIBLE | SS_LEFT);
SendMessage(h_maximum_bytes_billed_label, WM_SETFONT, (WPARAM)h_font, TRUE);
HWND h_maximum_bytes_billed_edit =
CreateEditBox(adv_hwnd, kinputComboBoxXAxis, kYAxis + 490, kEditBoxWidth,
CreateEditBox(adv_hwnd, kinputComboBoxXAxis, kYAxis + 485, kEditBoxWidth,
kEditBoxHeight, kIdcMaximumBytesBilledEdit);
SendMessage(h_maximum_bytes_billed_edit, WM_SETFONT, (WPARAM)h_font, TRUE);
SetWindowSubclass(GetDlgItem(adv_hwnd, kIdcMaximumBytesBilledEdit),
Expand All @@ -413,6 +415,19 @@ void AdvanceOptions::CreateAdditionalControls(HFONT h_font) {
GetWindowLongPtr(h_maximum_bytes_billed_edit, GWL_STYLE) |
ES_RIGHT | ES_NUMBER);

// allowed projects
HWND h_allowed_projects_label =
CreateLabel(adv_hwnd, "Allowed projects:", kXAxis, kYAxis + 510,
kWidth * 4 + 25, kHeight, WS_VISIBLE | SS_LEFT);
SendMessage(h_allowed_projects_label, WM_SETFONT, (WPARAM)h_font, TRUE);
HWND h_allowed_projects_edit =
CreateEditBox(adv_hwnd, kinputComboBoxXAxis, kYAxis + 510, kEditBoxWidth,
kEditBoxHeight, kIdcAllowedProjectsEdit);
SendMessage(h_allowed_projects_edit, WM_SETFONT, (WPARAM)h_font, TRUE);
SetWindowSubclass(GetDlgItem(adv_hwnd, kIdcAllowedProjectsEdit),
InputSubclassProc, 0, 0);
SetWindowText(h_allowed_projects_edit, allowed_projects_.c_str());

// TODO(b/497725655): Enable UI feature after public release
// HWND h_variables_checkbox = CreateCheckBox(
// adv_hwnd, "Use SQL_WVARCHAR instead of SQL_VARCHAR", kXAxis, kYAxis +
Expand All @@ -423,24 +438,24 @@ void AdvanceOptions::CreateAdditionalControls(HFONT h_font) {
// SetWindowSubclass(GetDlgItem(adv_hwnd, kIdcVariableCheckbox),
// CheckboxSubclassProc, 0, 0);
HWND h_additional_projects_label =
CreateLabel(adv_hwnd, "Additional projects:", kXAxis, kYAxis + 515,
CreateLabel(adv_hwnd, "Additional projects:", kXAxis, kYAxis + 535,
kWidth * 5, kHeight, WS_VISIBLE | SS_LEFT);
SendMessage(h_additional_projects_label, WM_SETFONT, (WPARAM)h_font, TRUE);
HWND h_additional_projects_edit =
CreateScrollableEditBox(adv_hwnd, kXAxis, kYAxis + 535, kWidth + 445,
kHeight + 16, kIdcAdditionalProjectsEdit);
CreateScrollableEditBox(adv_hwnd, kXAxis, kYAxis + 555, kWidth + 445,
kHeight + 6, kIdcAdditionalProjectsEdit);
SendMessage(h_additional_projects_edit, WM_SETFONT, (WPARAM)h_font, TRUE);

SetWindowText(h_additional_projects_edit, additional_projects_.c_str());
SetWindowSubclass(GetDlgItem(adv_hwnd, kIdcAdditionalProjectsEdit),
InputSubclassProc, 0, 0);

HWND h_query_properties_label =
CreateLabel(adv_hwnd, "Query properties:", kXAxis, kYAxis + 575,
CreateLabel(adv_hwnd, "Query properties:", kXAxis, kYAxis + 585,
kWidth * 5, kHeight, WS_VISIBLE | SS_LEFT);
SendMessage(h_query_properties_label, WM_SETFONT, (WPARAM)h_font, TRUE);
HWND h_query_properties_edit =
CreateScrollableEditBox(adv_hwnd, kXAxis, kYAxis + 595, kWidth + 445,
CreateScrollableEditBox(adv_hwnd, kXAxis, kYAxis + 605, kWidth + 445,
kHeight + 6, kIdcQueryPropertiesEdit);
SendMessage(h_query_properties_edit, WM_SETFONT, (WPARAM)h_font, TRUE);

Expand Down Expand Up @@ -681,6 +696,13 @@ LRESULT CALLBACK AdvanceOptions::AdvanceOptProc(HWND hwnd, UINT u_msg,
sizeof(additional_projects_buffer));
additional_projects_ = additional_projects_buffer;

HWND h_allowed_projects_edit =
GetDlgItem(hwnd, kIdcAllowedProjectsEdit);
char allowed_projects_buffer[1024] = {0};
GetWindowText(h_allowed_projects_edit, allowed_projects_buffer,
sizeof(allowed_projects_buffer));
allowed_projects_ = allowed_projects_buffer;

HWND h_query_properties_edit =
GetDlgItem(hwnd, kIdcQueryPropertiesEdit);
char query_properties_buffer[1024] = {0};
Expand Down Expand Up @@ -889,6 +911,7 @@ void AdvanceOptions::SetValues(Section const& attribute_map) {
enable_gcd_ = GetValueOrDefault(attribute_map, kEnableGcd);
universe_domain_ = GetValueOrDefault(attribute_map, kUniverseDomain);
maximum_bytes_billed_ = GetValueOrDefault(attribute_map, kMaximumBytesBilled);
allowed_projects_ = GetValueOrDefault(attribute_map, kAllowedProjects);
}

void AdvanceOptions::ResetToDefaults() {
Expand All @@ -914,6 +937,7 @@ void AdvanceOptions::ResetToDefaults() {
universe_domain_.clear();
// Unset means no cap, which is the shipped default.
maximum_bytes_billed_.clear();
allowed_projects_.clear();
}

void AdvanceOptions::Show(HWND hwnd) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#pragma comment(lib, "Comctl32.lib") // Link with Comctl32.lib

namespace google::cloud::odbc_bq_driver_internal {
// NEXTID:154
// NEXTID:155
static int const kIdcUseDefaultCheckbox = 128;
static int const kIdcDatasetNameEdit = 129;
static int const kIdcTempExpirationEdit = 130;
Expand All @@ -46,6 +46,7 @@ static int const kIdcEnablePscGcdCheckbox = 150;
static int const kIdcPrivateServiceNameEdit = 151;
static int const kIdcUniverseDomainEdit = 152;
static int const kIdcMaximumBytesBilledEdit = 153;
static int const kIdcAllowedProjectsEdit = 154;

class AdvanceOptions {
public:
Expand Down Expand Up @@ -109,6 +110,9 @@ class AdvanceOptions {
inline std::string const& GetMaximumBytesBilled() const {
return maximum_bytes_billed_;
}
inline std::string const& GetAllowedProjects() const {
return allowed_projects_;
}
void SetValues(Section const& attributes_map);
void ResetToDefaults();

Expand Down Expand Up @@ -141,6 +145,7 @@ class AdvanceOptions {
static std::string enable_gcd_;
static std::string universe_domain_;
static std::string maximum_bytes_billed_;
static std::string allowed_projects_;

static LRESULT CALLBACK AdvanceOptProc(HWND hwnd, UINT uMsg, WPARAM w_param,
LPARAM l_param);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,31 @@ TEST_F(AdvanceOptionsTest, ShowWindow) {
<< "Window should be visible after calling Show.";
}

TEST_F(AdvanceOptionsTest, AllowedProjectsRoundTripsThroughOk) {
// A saved value should appear in the field when the dialog opens, and OK
// should save back whatever the field then holds.
advance_options->SetValues({{"AllowedProjects", "project-a,project-b"}});

// Show() runs a modal GetMessage loop. Queue WM_QUIT first so it builds the
// controls and returns immediately instead of blocking this test; the window
// itself stays alive for the assertions below.
PostQuitMessage(0);
advance_options->Show(nullptr);
HWND hwnd = advance_options->GetHwnd();
ASSERT_NE(hwnd, nullptr) << "Window should be created and displayed.";

HWND h_edit = GetDlgItem(hwnd, kIdcAllowedProjectsEdit);
ASSERT_NE(h_edit, nullptr) << "Allowed projects field should be created.";
char buffer[256] = {0};
GetWindowText(h_edit, buffer, sizeof(buffer));
EXPECT_STREQ(buffer, "project-a,project-b");

SetWindowText(h_edit, "project-a");
ClickButton(hwnd, kIdcOKButton);

EXPECT_EQ(advance_options->GetAllowedProjects(), "project-a");
}

TEST_F(AdvanceOptionsTest, SetValuesValidinput) {
Section attribute_map = {{"SQLDialect", "1"},
{"LargeResultsDatasetId", "dataset1"},
Expand All @@ -81,6 +106,7 @@ TEST_F(AdvanceOptionsTest, SetValuesValidinput) {
{"LargeResultsTempTableExpirationTime", "3600000"},
{"SessionLocation", "USA"},
{"AdditionalProjects", "projectA,projectB"},
{"AllowedProjects", "projectC,projectD"},
{"QueryProperties", "property1=value1"},
{"MaxThreads", "10"},
{"MaxRetries", "9"}};
Expand All @@ -96,6 +122,7 @@ TEST_F(AdvanceOptionsTest, SetValuesValidinput) {
EXPECT_EQ(options.GetTempTableExpiration(), "3600000");
EXPECT_EQ(options.GetSessionLocation(), "USA");
EXPECT_EQ(options.GetAdditionalProjects(), "projectA,projectB");
EXPECT_EQ(options.GetAllowedProjects(), "projectC,projectD");
EXPECT_EQ(options.GetQueryProperties(), "property1=value1");
EXPECT_EQ(options.GetMaxThreads(), "10");
EXPECT_EQ(options.GetMaxRetries(), "9");
Expand All @@ -118,8 +145,19 @@ TEST_F(AdvanceOptionsTest, SetValuesMissingkeys) {
EXPECT_EQ(options.GetTempTableExpiration(), "3600000");
EXPECT_EQ(options.GetSessionLocation(), "");
EXPECT_EQ(options.GetAdditionalProjects(), "");
EXPECT_EQ(options.GetAllowedProjects(), "");
EXPECT_EQ(options.GetQueryProperties(), "");
EXPECT_EQ(options.GetAllowHtapiForLargeResultsCheckbox(), "");
}

TEST_F(AdvanceOptionsTest, ResetToDefaultsClearsAllowedProjects) {
AdvanceOptions options;
options.SetValues({{"AllowedProjects", "projectC,projectD"}});
ASSERT_EQ(options.GetAllowedProjects(), "projectC,projectD");

options.ResetToDefaults();

EXPECT_EQ(options.GetAllowedProjects(), "");
}

} // namespace google::cloud::odbc_bq_driver_internal
40 changes: 34 additions & 6 deletions google/cloud/odbc/bq_driver/internal/driver_form.cc
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ static Section BuildTestConnectionAttributes(
attributes_map["SessionLocation"] = adv_form.GetSessionLocation();
attributes_map["MaxThreads"] = adv_form.GetMaxThreads();
attributes_map["AdditionalProjects"] = adv_form.GetAdditionalProjects();
attributes_map["AllowedProjects"] = adv_form.GetAllowedProjects();
attributes_map["QueryProperties"] = adv_form.GetQueryProperties();
attributes_map["UseWVarChar"] = adv_form.GetUseWchar();
attributes_map["EnableSession"] = adv_form.GetEnableSession();
Expand All @@ -242,7 +243,8 @@ static Section BuildTestConnectionAttributes(

StatusRecordOr<std::string> DriverForm::GetCatalogAndDataset(
std::string const& action, std::string const& key_file_path,
std::string const& oauth_token, std::string const& catalog_name) {
std::string const& oauth_token, std::string const& catalog_name,
std::string const& trusted_certs, bool use_system_trust_store) {
OauthMechanism oauth_value;
if (oauth_token == "Service Authentication") {
oauth_value = OauthMechanism::kServiceAccount;
Expand All @@ -259,9 +261,27 @@ StatusRecordOr<std::string> DriverForm::GetCatalogAndDataset(
oauth_value = OauthMechanism::kExternalUser;
}

ConnProps conn_props;
conn_props.auth_mechanism = oauth_value;
conn_props.credentials_file_path = key_file_path;
conn_props.ssl_credentials.pem_root_certs =
!trusted_certs.empty() ? trusted_certs : GetDefaultPemFile();
conn_props.ssl_credentials.use_system_trust_store = use_system_trust_store;

ProxyOptions proxy_form;
conn_props.proxy_options.hostname = proxy_form.GetProxyHost();
conn_props.proxy_options.port = proxy_form.GetProxyPort();
conn_props.proxy_options.username = proxy_form.GetProxyUsername();
conn_props.proxy_options.password = proxy_form.GetProxyPass();

AdvanceOptions adv_form;
conn_props.psc = adv_form.GetPrivateServiceConnectUris();
conn_props.gcd.enable_gcd =
(adv_form.GetEnableGcd() == "1" || adv_form.GetEnableGcd() == "true");
conn_props.gcd.universe_domain = adv_form.GetUniverseDomain();

SQLULEN metadata_id = 0;
auto bq_client_ptr =
ODBCBQClient::CreateBQClient({oauth_value, key_file_path});
auto bq_client_ptr = ODBCBQClient::CreateBQClient(conn_props);
if (!bq_client_ptr) {
return bq_client_ptr.GetStatusRecord();
}
Expand Down Expand Up @@ -765,11 +785,13 @@ void EvaluateFields(HWND hwnd) {

void PopulateDropdown(HWND h_dataset_box, std::string text,
std::string key_file, std::string conn_props,
std::string catalog) {
std::string catalog, std::string trusted_certs = "",
bool use_system_trust_store = false) {
SendMessage(h_dataset_box, CB_RESETCONTENT, 0, 0);

StatusRecordOr<std::string> status_record =
DriverForm::GetCatalogAndDataset(text, key_file, conn_props, catalog);
DriverForm::GetCatalogAndDataset(text, key_file, conn_props, catalog,
trusted_certs, use_system_trust_store);

if (!status_record.Ok()) {
MessageBox(h_dataset_box, status_record.GetStatusRecord().message.c_str(),
Expand Down Expand Up @@ -826,8 +848,14 @@ StatusRecord HandleDropdown(HWND hwnd, int control_id, char const* field_type,

if (has_auth && has_catalog && (is_adc || has_key)) {
char const* key_to_use = is_adc ? "" : key_buffer;
char trusted_cert_buffer[256] = {};
RetrieveFieldText(hwnd, kIdcTrustedCertEdit, trusted_cert_buffer,
sizeof(trusted_cert_buffer));
bool use_system_trust_store =
(IsDlgButtonChecked(hwnd, kIdcSystemTrustStoreCheckbox) == BST_CHECKED);
PopulateDropdown(h_control, field_type, key_to_use, auth_buffer,
catalog_buffer);
catalog_buffer, trusted_cert_buffer,
use_system_trust_store);
return StatusRecord::Ok();
}

Expand Down
4 changes: 3 additions & 1 deletion google/cloud/odbc/bq_driver/internal/driver_form.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ class DriverForm {

static odbc_internal::StatusRecordOr<std::string> GetCatalogAndDataset(
std::string const& action, std::string const& key_file_path,
std::string const& oauth_token, std::string const& catalog_name = "");
std::string const& oauth_token, std::string const& catalog_name = "",
std::string const& trusted_certs = "",
bool use_system_trust_store = false);

inline void SetLogTraceValues(Section const& attributes_map) {
log_trace_dialog_.SetValues(attributes_map);
Expand Down
1 change: 1 addition & 0 deletions google/cloud/odbc/bq_driver/internal/odbc_conn_handle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ void ConnectionHandle::SetUp(Section& dsn_section,
dsn_.kms_key_name = dsn_section["KMSKEYNAME"];
dsn_.session_location = dsn_section["SESSIONLOCATION"];
dsn_.additional_projects = dsn_section["ADDITIONALPROJECTS"];
dsn_.allowed_projects = dsn_section["ALLOWEDPROJECTS"];
dsn_.psc = dsn_section["PRIVATESERVICECONNECTURIS"];
dsn_.enable_gcd =
dsn_section["ENABLEGCD"] == "1" || dsn_section["ENABLEGCD"] == "true";
Expand Down
1 change: 1 addition & 0 deletions google/cloud/odbc/bq_driver/internal/odbc_conn_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ struct Dsn {
// Proxy options fields
google::cloud::odbc_bigquery_client_interface::ProxyOptions proxy_options;
std::string additional_projects;
std::string allowed_projects;
std::string psc;
bool enable_gcd;
std::string universe_domain;
Expand Down
23 changes: 23 additions & 0 deletions google/cloud/odbc/bq_driver/internal/odbc_conn_handle_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,29 @@ TEST(ConnectionHandle, DsnSetupListProjectsParentSet) {
EXPECT_EQ(actual.list_projects_parent, kDsnListProjectsParent);
}

TEST(ConnectionHandle, DsnSetupAllowedProjectsNotSet) {
ConnectionHandle conn_handle;
Section dsn_section;

conn_handle.SetUp(dsn_section, kDsnName);

Dsn actual = conn_handle.GetDsn();
EXPECT_TRUE(actual.allowed_projects.empty());
}

TEST(ConnectionHandle, DsnSetupAllowedProjectsSet) {
ConnectionHandle conn_handle;
Section dsn_section;

dsn_section["ALLOWEDPROJECTS"] = "project-1,project-2";
conn_handle.SetUp(dsn_section, kDsnName);

Dsn actual = conn_handle.GetDsn();
EXPECT_EQ(actual.allowed_projects, "project-1,project-2");
// AdditionalProjects and AllowedProjects are independent settings.
EXPECT_TRUE(actual.additional_projects.empty());
}

TEST(ConnectionHandle, SetAttributeSuccessSQLUInt) {
ConnectionHandle conn_handle;

Expand Down
Loading
Loading