aws_advanced_ruby_driver_wrapper 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE +175 -0
- data/NOTICE +1 -0
- data/README.md +168 -0
- data/THIRD-PARTY-LICENSES +473 -0
- data/aws_advanced_ruby_driver_wrapper.gemspec +73 -0
- data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_mysql2_adapter.rb +73 -0
- data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_postgresql_adapter.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/custom_configuration.rb +58 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_mysql_dialect.rb +103 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_pg_dialect.rb +124 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/dialect_codes.rb +38 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_mysql_dialect.rb +91 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_pg_dialect.rb +92 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_mysql_dialect.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_pg_dialect.rb +86 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/mysql_dialect.rb +98 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/pg_dialect.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_mysql_dialect.rb +88 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_pg_dialect.rb +86 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/unknown_dialect.rb +72 -0
- data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/utils/dialect_utils.rb +71 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect.rb +154 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect_manager.rb +55 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/mysql_driver_dialect.rb +165 -0
- data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/pg_driver_dialect.rb +201 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors/error_handler.rb +62 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors/mysql_error_handler.rb +80 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors/pg_error_handler.rb +126 -0
- data/lib/aws_advanced_ruby_driver_wrapper/errors.rb +59 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/connection_string_host_list_provider.rb +95 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/global_aurora_host_list_provider.rb +65 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability.rb +24 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability_strategy.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_info.rb +137 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/host_role.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/random_host_selector.rb +40 -0
- data/lib/aws_advanced_ruby_driver_wrapper/host/rds_host_list_provider.rb +206 -0
- data/lib/aws_advanced_ruby_driver_wrapper/logging.rb +110 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/cluster_topology_monitor.rb +709 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/global_cluster_topology_monitor.rb +72 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor.rb +99 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_connection.rb +57 -0
- data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_state.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/mysql.rb +429 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/blue_green_plugin.rb +205 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/host_mapper.rb +132 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/iam_host_tracker.rb +84 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interim_status.rb +92 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interval_rate.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase.rb +69 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_event_log.rb +85 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_time_info.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/role.rb +38 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/base_routing.rb +83 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/reject_connect_routing.rb +40 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/substitute_connect_routing.rb +136 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_connect_routing.rb +53 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_execute_routing.rb +52 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_until_corresponding_host_found_connect_routing.rb +83 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status.rb +68 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_builder.rb +244 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_info.rb +30 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_monitor.rb +564 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_provider.rb +414 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_state.rb +98 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_timer.rb +46 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_monitor.rb +266 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_plugin.rb +158 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/info.rb +111 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/member_list_type.rb +31 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/role.rb +45 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/default_plugin.rb +108 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_mode.rb +43 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_plugin.rb +467 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_mode.rb +68 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_plugin.rb +403 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/iam_auth_plugin.rb +159 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/initial_connection_strategy_plugin.rb +485 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/audit_logger.rb +157 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_cipher.rb +159 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_encryption_config.rb +61 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/connection_source.rb +91 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/data_key_cache.rb +220 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_algorithm.rb +75 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_config.rb +146 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_service.rb +391 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/error_context.rb +198 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/errors.rb +259 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_management_utility.rb +435 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_manager.rb +378 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_metadata.rb +86 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_plugin.rb +890 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_utility.rb +281 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/metadata_manager.rb +332 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sanitizer.rb +147 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_name.rb +70 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_validator.rb +211 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sql_runner.rb +147 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/type_marker.rb +109 -0
- data/lib/aws_advanced_ruby_driver_wrapper/plugins/secrets_manager_plugin.rb +358 -0
- data/lib/aws_advanced_ruby_driver_wrapper/postgresql.rb +659 -0
- data/lib/aws_advanced_ruby_driver_wrapper/property_definition.rb +409 -0
- data/lib/aws_advanced_ruby_driver_wrapper/ruby_method.rb +122 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/connection_service.rb +143 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/dialect_service.rb +267 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/host_service.rb +199 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/monitor_service.rb +186 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_call_context.rb +63 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_manager.rb +273 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/service_container.rb +30 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/service_utility.rb +78 -0
- data/lib/aws_advanced_ruby_driver_wrapper/services/session_state_service.rb +56 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/accessible_regions.rb +52 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/ar_constants.rb +25 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/aurora_topology_utils.rb +99 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/aws_credentials_utils.rb +62 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config.rb +91 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config_parser.rb +368 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/conversion_utils.rb +51 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/events/batching_event_publisher.rb +119 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/events/data_access_event.rb +26 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/events/monitor_reset_event.rb +26 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/global_aurora_topology_utils.rb +185 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/host_list_utils.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/iam_auth_utils.rb +112 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/multi_az_topology_utils.rb +117 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/encryption_annotation_parser.rb +99 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/mysql_statement_analyzer.rb +641 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/pg_statement_analyzer.rb +502 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_analysis.rb +63 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_type.rb +35 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint.rb +27 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint_parser.rb +50 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/sql_parser.rb +139 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_url_type.rb +71 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_utils.rb +575 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/retry_util.rb +153 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_encoding.rb +56 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_method_analyzer.rb +195 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/cache_entry.rb +56 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/expiration_cache.rb +108 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/sliding_expiration_cache.rb +137 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/storage_service.rb +172 -0
- data/lib/aws_advanced_ruby_driver_wrapper/utils/topology_utils.rb +127 -0
- data/lib/aws_advanced_ruby_driver_wrapper/version.rb +19 -0
- data/lib/aws_advanced_ruby_driver_wrapper/wrapper_property.rb +64 -0
- data/lib/aws_advanced_ruby_driver_wrapper.rb +116 -0
- metadata +227 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative '../ruby_method'
|
|
18
|
+
require_relative '../logging'
|
|
19
|
+
|
|
20
|
+
module AwsAdvancedRubyDriverWrapper
|
|
21
|
+
module DriverDialects
|
|
22
|
+
module DriverDialect
|
|
23
|
+
include Logging
|
|
24
|
+
|
|
25
|
+
COMMON_NETWORK_BOUND_METHODS = Set[
|
|
26
|
+
RubyMethod::CONNECT.name,
|
|
27
|
+
RubyMethod::CONNECTION_CLOSE.name,
|
|
28
|
+
RubyMethod::CONNECTION_RESET.name,
|
|
29
|
+
RubyMethod::CONNECTION_PREPARE.name,
|
|
30
|
+
RubyMethod::STATEMENT_EXECUTE.name,
|
|
31
|
+
RubyMethod::STATEMENT_CLOSE.name
|
|
32
|
+
].freeze
|
|
33
|
+
|
|
34
|
+
DEFAULT_MONITORING_TIMEOUT_SEC = 5
|
|
35
|
+
|
|
36
|
+
def connect(host_info, config)
|
|
37
|
+
raise NotImplementedError
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def execute(connection, sql)
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def execute_with_params(connection, sql, params)
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Rewrites +?+ placeholders into the driver's native placeholder syntax.
|
|
49
|
+
# @param sql [String] SQL written with +?+ placeholders
|
|
50
|
+
# @return [String]
|
|
51
|
+
def translate_placeholders(sql)
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Wraps binary data as the bind value the driver needs for a bytea/blob parameter.
|
|
56
|
+
# @param bytes [String] binary data
|
|
57
|
+
# @return [Object] the driver-specific bind value
|
|
58
|
+
def binary_param(bytes)
|
|
59
|
+
raise NotImplementedError
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Reads a bytea/blob column value back into binary data.
|
|
63
|
+
# @param value [String] the raw column value
|
|
64
|
+
# @return [String] binary data
|
|
65
|
+
def read_binary(value)
|
|
66
|
+
raise NotImplementedError
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The number of rows an INSERT, UPDATE, or DELETE changed.
|
|
70
|
+
# @param connection [Object] the driver connection
|
|
71
|
+
# @param result [Object] the value the statement returned
|
|
72
|
+
# @return [Integer]
|
|
73
|
+
def affected_rows(connection, result)
|
|
74
|
+
raise NotImplementedError
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Runs an INSERT and returns the id it generated.
|
|
78
|
+
# @param sql [String] native SQL for the INSERT, without a RETURNING clause
|
|
79
|
+
# @param id_column [String] the generated column to return
|
|
80
|
+
# @return [Integer, nil]
|
|
81
|
+
def insert_returning_id(connection, sql, params, id_column)
|
|
82
|
+
raise NotImplementedError
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The trailing upsert clause for an INSERT, in the driver's own grammar.
|
|
86
|
+
# @param conflict_columns [Array<String>] the columns whose conflict triggers the update
|
|
87
|
+
# @param update_columns [Array<String>] the columns to overwrite from the incoming row
|
|
88
|
+
# @return [String]
|
|
89
|
+
def upsert_clause(conflict_columns, update_columns)
|
|
90
|
+
raise NotImplementedError
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The equality operator for the wrapper's own SQL, in the driver's own grammar.
|
|
94
|
+
# @return [String]
|
|
95
|
+
def equals_operator
|
|
96
|
+
raise NotImplementedError
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# A query returning a table's foreign keys as rows with +from_column+, +to_table+, and
|
|
100
|
+
# +to_column+, using +?+ placeholders for the schema and table names.
|
|
101
|
+
# @return [String]
|
|
102
|
+
def foreign_key_query
|
|
103
|
+
raise NotImplementedError
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def ping(connection)
|
|
107
|
+
raise NotImplementedError
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def closed?(connection)
|
|
111
|
+
raise NotImplementedError
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def close_connection(connection)
|
|
115
|
+
raise NotImplementedError
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def sql_state(_exception)
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def network_bound_methods
|
|
123
|
+
COMMON_NETWORK_BOUND_METHODS
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def prepare_connect_config(host_info, config)
|
|
127
|
+
raise NotImplementedError
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Returns the property key the underlying driver expects for the database username.
|
|
131
|
+
# Override in driver-specific dialects where the key differs.
|
|
132
|
+
def user_property_key
|
|
133
|
+
:user
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Applies default socket/connect timeouts to monitoring connection driver props.
|
|
137
|
+
# These ensure that a query or close on a dead connection raises a timeout error
|
|
138
|
+
# rather than hanging indefinitely or segfaulting.
|
|
139
|
+
# Implementations should only apply these properties if the user hasn't already set them.
|
|
140
|
+
# @param driver_props [Hash] the monitoring connection driver props (mutated in place)
|
|
141
|
+
def apply_monitoring_defaults(driver_props)
|
|
142
|
+
# No-op by default; driver-specific dialects override.
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Returns +true+/+false+ if the driver can report transaction state directly,
|
|
146
|
+
# or +nil+ if it cannot (SQL inference is used as fallback).
|
|
147
|
+
# @param connection [Object]
|
|
148
|
+
# @return [Boolean, nil]
|
|
149
|
+
def reported_in_transaction(_connection)
|
|
150
|
+
nil
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'mysql_driver_dialect'
|
|
18
|
+
require_relative 'pg_driver_dialect'
|
|
19
|
+
require_relative '../errors'
|
|
20
|
+
require_relative '../errors/mysql_error_handler'
|
|
21
|
+
require_relative '../errors/pg_error_handler'
|
|
22
|
+
|
|
23
|
+
module AwsAdvancedRubyDriverWrapper
|
|
24
|
+
module DriverDialects
|
|
25
|
+
module DriverDialectManager
|
|
26
|
+
MYSQL_DIALECT = MysqlDriverDialect.new.freeze
|
|
27
|
+
PG_DIALECT = PgDriverDialect.new.freeze
|
|
28
|
+
|
|
29
|
+
REGISTRY = {
|
|
30
|
+
mysql2: {
|
|
31
|
+
driver_dialect: MYSQL_DIALECT,
|
|
32
|
+
error_handler: Errors::MysqlErrorHandler.new(MYSQL_DIALECT)
|
|
33
|
+
},
|
|
34
|
+
postgresql: {
|
|
35
|
+
driver_dialect: PG_DIALECT,
|
|
36
|
+
error_handler: Errors::PgErrorHandler.new(PG_DIALECT)
|
|
37
|
+
}
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
def self.get_dialect(driver_name)
|
|
41
|
+
fetch_entry(driver_name)[:driver_dialect]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.get_error_handler(driver_name)
|
|
45
|
+
fetch_entry(driver_name)[:error_handler]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.fetch_entry(driver_name)
|
|
49
|
+
REGISTRY.fetch(driver_name) do
|
|
50
|
+
raise Errors::AwsError, "Unknown driver: #{driver_name}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'driver_dialect'
|
|
18
|
+
require_relative '../host/connection_string_host_list_provider'
|
|
19
|
+
|
|
20
|
+
module AwsAdvancedRubyDriverWrapper
|
|
21
|
+
module DriverDialects
|
|
22
|
+
class MysqlDriverDialect
|
|
23
|
+
include DriverDialect
|
|
24
|
+
|
|
25
|
+
# Every mysql2 call that talks to the server. A call that is not listed here is handed straight
|
|
26
|
+
# to the driver, bypassing the plugin pipeline.
|
|
27
|
+
#
|
|
28
|
+
# Not listed, because libmysql answers them without talking to the server: escape, the row and
|
|
29
|
+
# column counts, last_id, affected_rows, info, warning_count, thread_id, server_info,
|
|
30
|
+
# session_track, and the connection's own settings.
|
|
31
|
+
NETWORK_BOUND_METHODS = (COMMON_NETWORK_BOUND_METHODS | Set[
|
|
32
|
+
RubyMethod::CONNECTION_QUERY.name,
|
|
33
|
+
RubyMethod::CONNECTION_ASYNC_RESULT.name,
|
|
34
|
+
RubyMethod::CONNECTION_SELECT_DB.name,
|
|
35
|
+
RubyMethod::CONNECTION_MORE_RESULTS.name,
|
|
36
|
+
RubyMethod::CONNECTION_NEXT_RESULT.name,
|
|
37
|
+
RubyMethod::CONNECTION_STORE_RESULT.name,
|
|
38
|
+
RubyMethod::CONNECTION_ABANDON_RESULTS.name,
|
|
39
|
+
RubyMethod::CONNECTION_SET_SERVER_OPTION.name,
|
|
40
|
+
RubyMethod::RESULT_EACH.name,
|
|
41
|
+
RubyMethod::RESULT_FREE.name
|
|
42
|
+
]).freeze
|
|
43
|
+
|
|
44
|
+
def connect(host_info, config)
|
|
45
|
+
::Mysql2::Client.new(**prepare_connect_config(host_info, config))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def execute(connection, sql)
|
|
49
|
+
raise Mysql2::Error, 'MySQL client is not connected' if connection.nil? || connection.closed?
|
|
50
|
+
|
|
51
|
+
connection.query(sql)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def execute_with_params(connection, sql, params)
|
|
55
|
+
raise Mysql2::Error, 'MySQL client is not connected' if connection.nil? || connection.closed?
|
|
56
|
+
|
|
57
|
+
stmt = connection.prepare(sql)
|
|
58
|
+
result = stmt.execute(*params)
|
|
59
|
+
# Everything the caller needs must be read off the statement before the ensure closes its
|
|
60
|
+
# handle. A SELECT result is bound to the handle, so materialize its rows now - otherwise a
|
|
61
|
+
# later iteration (e.g. SqlRunner calling #to_a) raises "Statement handle already closed".
|
|
62
|
+
# A non-SELECT statement returns nil, and its affected-row count must come from the statement
|
|
63
|
+
# too: once the handle is closed the connection-level mysql_affected_rows returns its -1 error
|
|
64
|
+
# sentinel and mysql2 raises. So return that count for #affected_rows to hand back.
|
|
65
|
+
result.is_a?(::Mysql2::Result) ? result.to_a : stmt.affected_rows
|
|
66
|
+
ensure
|
|
67
|
+
stmt&.close
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# mysql2 uses +?+ placeholders, so the SQL is already in its native form.
|
|
71
|
+
def translate_placeholders(sql)
|
|
72
|
+
sql
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# mysql2 binds a blob parameter as raw binary bytes.
|
|
76
|
+
def binary_param(bytes)
|
|
77
|
+
bytes.b
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# mysql2 hands back a blob column as a string that only needs its encoding forced to binary.
|
|
81
|
+
def read_binary(value)
|
|
82
|
+
value.b
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# A prepared statement (execute_with_params) hands back its own affected-row count, since the
|
|
86
|
+
# connection-level count is unreadable once the statement handle is closed. A plain
|
|
87
|
+
# connection.query (execute) leaves nil, so the count is read off the connection instead.
|
|
88
|
+
def affected_rows(connection, result)
|
|
89
|
+
result.is_a?(Integer) ? result : connection.affected_rows.to_i
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# mysql2 has no RETURNING clause, so the generated id is read from the connection afterwards.
|
|
93
|
+
def insert_returning_id(connection, sql, params, _id_column)
|
|
94
|
+
execute_with_params(connection, sql, params)
|
|
95
|
+
id = connection.last_id
|
|
96
|
+
id&.positive? ? id : nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# mysql2 upserts with ON DUPLICATE KEY UPDATE, reading the incoming row from VALUES().
|
|
100
|
+
def upsert_clause(_conflict_columns, update_columns)
|
|
101
|
+
assignments = update_columns.map { |column| "#{column} = VALUES(#{column})" }.join(', ')
|
|
102
|
+
"ON DUPLICATE KEY UPDATE #{assignments}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# MySQL has no user-defined operators, so the plain operator always means the built-in one.
|
|
106
|
+
def equals_operator
|
|
107
|
+
'='
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def foreign_key_query
|
|
111
|
+
'SELECT column_name AS from_column, referenced_table_name AS to_table, ' \
|
|
112
|
+
'referenced_column_name AS to_column FROM information_schema.key_column_usage ' \
|
|
113
|
+
'WHERE table_schema = ? AND table_name = ? AND referenced_table_name IS NOT NULL'
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def ping(connection)
|
|
117
|
+
connection.ping
|
|
118
|
+
rescue StandardError
|
|
119
|
+
false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def closed?(connection)
|
|
123
|
+
connection.nil? || connection.closed?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def close_connection(connection)
|
|
127
|
+
return if connection.nil? || connection.closed?
|
|
128
|
+
|
|
129
|
+
connection.close
|
|
130
|
+
rescue StandardError => e
|
|
131
|
+
logger.error("Failed to close MySQL connection: #{e.message}")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def sql_state(exception)
|
|
135
|
+
return nil unless exception.respond_to?(:sql_state)
|
|
136
|
+
|
|
137
|
+
exception.sql_state
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def network_bound_methods
|
|
141
|
+
NETWORK_BOUND_METHODS
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def prepare_connect_config(host_info, config)
|
|
145
|
+
cfg = {}
|
|
146
|
+
config.each { |k, v| cfg[k] = v }
|
|
147
|
+
cfg[:host] = host_info.host if host_info.host_specified?
|
|
148
|
+
cfg[:port] = host_info.port.to_i if host_info.port_specified?
|
|
149
|
+
cfg
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def user_property_key
|
|
153
|
+
:username
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def apply_monitoring_defaults(driver_props)
|
|
157
|
+
# mysql2 read_timeout / write_timeout (in seconds) ensure that queries and closes
|
|
158
|
+
# on a dead socket raise Mysql2::Error::TimeoutError instead of segfaulting.
|
|
159
|
+
driver_props[:read_timeout] ||= DEFAULT_MONITORING_TIMEOUT_SEC
|
|
160
|
+
driver_props[:write_timeout] ||= DEFAULT_MONITORING_TIMEOUT_SEC
|
|
161
|
+
driver_props[:connect_timeout] ||= DEFAULT_MONITORING_TIMEOUT_SEC
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
require_relative 'driver_dialect'
|
|
18
|
+
|
|
19
|
+
module AwsAdvancedRubyDriverWrapper
|
|
20
|
+
module DriverDialects
|
|
21
|
+
class PgDriverDialect
|
|
22
|
+
include DriverDialect
|
|
23
|
+
|
|
24
|
+
# Every pg call that talks to the server. A call that is not listed here is handed straight
|
|
25
|
+
# to the driver, bypassing the plugin pipeline.
|
|
26
|
+
#
|
|
27
|
+
# pg gives most of these operations several spellings (+query+ and +async_query+ for +exec+, an
|
|
28
|
+
# +async_+ and a +sync_+ form for many others, a short +lo*+ form for every large object call).
|
|
29
|
+
# One entry covers every spelling of a libpq operation: WrapperPgConnection recognizes which operation a
|
|
30
|
+
# spelling performs and enters the pipeline under that name, then asks the driver for the spelling
|
|
31
|
+
# it was given. Its OPERATIONS table has an entry per name listed here.
|
|
32
|
+
#
|
|
33
|
+
# Not listed, because libpq performs them without talking to the server: enter_pipeline_mode,
|
|
34
|
+
# exit_pipeline_mode, is_busy, setnonblocking, set_single_row_mode, set_chunked_rows_mode, the
|
|
35
|
+
# escaping and quoting calls, and the accessors for connection parameters and type maps.
|
|
36
|
+
NETWORK_BOUND_METHODS = (COMMON_NETWORK_BOUND_METHODS | Set[
|
|
37
|
+
RubyMethod::CONNECTION_EXEC.name,
|
|
38
|
+
RubyMethod::CONNECTION_ASYNC_EXEC.name,
|
|
39
|
+
RubyMethod::CONNECTION_EXEC_PARAMS.name,
|
|
40
|
+
RubyMethod::CONNECTION_EXEC_PREPARED.name,
|
|
41
|
+
RubyMethod::CONNECTION_DESCRIBE_PREPARED.name,
|
|
42
|
+
RubyMethod::CONNECTION_DESCRIBE_PORTAL.name,
|
|
43
|
+
RubyMethod::CONNECTION_TRANSACTION.name,
|
|
44
|
+
RubyMethod::CONNECTION_COPY_DATA.name,
|
|
45
|
+
RubyMethod::CONNECTION_PUT_COPY_DATA.name,
|
|
46
|
+
RubyMethod::CONNECTION_GET_COPY_DATA.name,
|
|
47
|
+
RubyMethod::CONNECTION_PUT_COPY_END.name,
|
|
48
|
+
RubyMethod::CONNECTION_SEND_QUERY.name,
|
|
49
|
+
RubyMethod::CONNECTION_SEND_QUERY_PARAMS.name,
|
|
50
|
+
RubyMethod::CONNECTION_SEND_QUERY_PREPARED.name,
|
|
51
|
+
RubyMethod::CONNECTION_SEND_PREPARE.name,
|
|
52
|
+
RubyMethod::CONNECTION_GET_RESULT.name,
|
|
53
|
+
RubyMethod::CONNECTION_GET_LAST_RESULT.name,
|
|
54
|
+
RubyMethod::CONNECTION_CANCEL.name,
|
|
55
|
+
RubyMethod::CONNECTION_SET_CLIENT_ENCODING.name,
|
|
56
|
+
RubyMethod::CONNECTION_WAIT_FOR_NOTIFY.name,
|
|
57
|
+
RubyMethod::CONNECTION_NOTIFIES.name,
|
|
58
|
+
RubyMethod::CONNECTION_CONSUME_INPUT.name,
|
|
59
|
+
RubyMethod::CONNECTION_FLUSH.name,
|
|
60
|
+
RubyMethod::CONNECTION_LO_OPEN.name,
|
|
61
|
+
RubyMethod::CONNECTION_LO_READ.name,
|
|
62
|
+
RubyMethod::CONNECTION_LO_WRITE.name,
|
|
63
|
+
RubyMethod::CONNECTION_LO_CLOSE.name,
|
|
64
|
+
RubyMethod::CONNECTION_CLOSE_PREPARED.name,
|
|
65
|
+
RubyMethod::CONNECTION_CLOSE_PORTAL.name,
|
|
66
|
+
RubyMethod::CONNECTION_DISCARD_RESULTS.name,
|
|
67
|
+
RubyMethod::CONNECTION_SEND_DESCRIBE_PREPARED.name,
|
|
68
|
+
RubyMethod::CONNECTION_SEND_DESCRIBE_PORTAL.name,
|
|
69
|
+
RubyMethod::CONNECTION_SEND_FLUSH_REQUEST.name,
|
|
70
|
+
RubyMethod::CONNECTION_PIPELINE_SYNC.name,
|
|
71
|
+
RubyMethod::CONNECTION_SEND_PIPELINE_SYNC.name,
|
|
72
|
+
RubyMethod::CONNECTION_BLOCK.name,
|
|
73
|
+
RubyMethod::CONNECTION_RESET_START.name,
|
|
74
|
+
RubyMethod::CONNECTION_RESET_POLL.name,
|
|
75
|
+
RubyMethod::CONNECTION_ENCRYPT_PASSWORD.name,
|
|
76
|
+
RubyMethod::CONNECTION_SET_DEFAULT_ENCODING.name,
|
|
77
|
+
RubyMethod::CONNECTION_INTERNAL_ENCODING_SET.name,
|
|
78
|
+
RubyMethod::CONNECTION_LO_CREAT.name,
|
|
79
|
+
RubyMethod::CONNECTION_LO_CREATE.name,
|
|
80
|
+
RubyMethod::CONNECTION_LO_IMPORT.name,
|
|
81
|
+
RubyMethod::CONNECTION_LO_EXPORT.name,
|
|
82
|
+
RubyMethod::CONNECTION_LO_UNLINK.name,
|
|
83
|
+
RubyMethod::CONNECTION_LO_LSEEK.name,
|
|
84
|
+
RubyMethod::CONNECTION_LO_TELL.name,
|
|
85
|
+
RubyMethod::CONNECTION_LO_TRUNCATE.name
|
|
86
|
+
]).freeze
|
|
87
|
+
|
|
88
|
+
def connect(host_info, config)
|
|
89
|
+
::PG::Connection.new(**prepare_connect_config(host_info, config))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def execute(connection, sql)
|
|
93
|
+
connection.exec(sql)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def execute_with_params(connection, sql, params)
|
|
97
|
+
connection.exec_params(sql, params)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# pg uses numbered +$1+, +$2+ ... placeholders.
|
|
101
|
+
def translate_placeholders(sql)
|
|
102
|
+
index = 0
|
|
103
|
+
sql.gsub('?') do
|
|
104
|
+
index += 1
|
|
105
|
+
"$#{index}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# pg binds a bytea parameter as a value tagged with binary format 1.
|
|
110
|
+
def binary_param(bytes)
|
|
111
|
+
{ value: bytes, format: 1 }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# pg hands back a bytea column in its hex (or older octal) text format.
|
|
115
|
+
def read_binary(value)
|
|
116
|
+
::PG::Connection.unescape_bytea(value)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# pg reports the affected row count on the result.
|
|
120
|
+
def affected_rows(_connection, result)
|
|
121
|
+
result.respond_to?(:cmd_tuples) ? result.cmd_tuples.to_i : 0
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# pg returns the generated id with a RETURNING clause.
|
|
125
|
+
def insert_returning_id(connection, sql, params, id_column)
|
|
126
|
+
row = execute_with_params(connection, "#{sql} RETURNING #{id_column}", params)&.first
|
|
127
|
+
row && row[id_column].to_i
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# pg upserts with ON CONFLICT ... DO UPDATE, reading the incoming row from EXCLUDED.
|
|
131
|
+
def upsert_clause(conflict_columns, update_columns)
|
|
132
|
+
assignments = update_columns.map { |column| "#{column} = EXCLUDED.#{column}" }.join(', ')
|
|
133
|
+
"ON CONFLICT (#{conflict_columns.join(', ')}) DO UPDATE SET #{assignments}"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# pg resolves an unqualified operator through the search_path, where a user-defined operator
|
|
137
|
+
# with a closer type match would be chosen over the built-in one, so pin it to pg_catalog.
|
|
138
|
+
def equals_operator
|
|
139
|
+
'OPERATOR(pg_catalog.=)'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def foreign_key_query
|
|
143
|
+
eq = equals_operator
|
|
144
|
+
'SELECT kcu.column_name AS from_column, ccu.table_name AS to_table, ccu.column_name AS to_column ' \
|
|
145
|
+
'FROM information_schema.table_constraints tc ' \
|
|
146
|
+
'JOIN information_schema.key_column_usage kcu ' \
|
|
147
|
+
"ON tc.constraint_name #{eq} kcu.constraint_name AND tc.table_schema #{eq} kcu.table_schema " \
|
|
148
|
+
'JOIN information_schema.constraint_column_usage ccu ' \
|
|
149
|
+
"ON tc.constraint_name #{eq} ccu.constraint_name AND tc.table_schema #{eq} ccu.table_schema " \
|
|
150
|
+
"WHERE tc.constraint_type #{eq} 'FOREIGN KEY' AND tc.table_schema #{eq} $1 AND tc.table_name #{eq} $2"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def closed?(connection)
|
|
154
|
+
connection.finished? || connection.status != ::PG::CONNECTION_OK
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def close_connection(connection)
|
|
158
|
+
return if connection.nil? || connection.finished?
|
|
159
|
+
|
|
160
|
+
connection.close
|
|
161
|
+
rescue StandardError => e
|
|
162
|
+
logger.error("Failed to close PostgreSQL connection: #{e.message}")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def sql_state(exception)
|
|
166
|
+
return nil unless exception.is_a?(::PG::Error) && exception.result
|
|
167
|
+
|
|
168
|
+
exception.result.error_field(::PG::PG_DIAG_SQLSTATE)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def network_bound_methods
|
|
172
|
+
NETWORK_BOUND_METHODS
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def prepare_connect_config(host_info, config)
|
|
176
|
+
cfg = {}
|
|
177
|
+
config.each { |k, v| cfg[k] = v }
|
|
178
|
+
cfg[:host] = host_info.host if host_info.host_specified?
|
|
179
|
+
cfg[:port] = host_info.port if host_info.port_specified?
|
|
180
|
+
cfg[:dbname] = cfg.delete(:database) if !cfg.key?(:dbname) && cfg.key?(:database)
|
|
181
|
+
cfg
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def apply_monitoring_defaults(driver_props)
|
|
185
|
+
driver_props[:connect_timeout] ||= DEFAULT_MONITORING_TIMEOUT_SEC
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# PG reads transaction state directly from the connection.
|
|
189
|
+
# Returns nil for PQTRANS_UNKNOWN (broken) and PQTRANS_ACTIVE (command in flight)
|
|
190
|
+
# so SessionStateService falls back to SQL inference.
|
|
191
|
+
def reported_in_transaction(connection)
|
|
192
|
+
case connection.transaction_status
|
|
193
|
+
when ::PG::PQTRANS_INTRANS, ::PG::PQTRANS_INERROR then true
|
|
194
|
+
when ::PG::PQTRANS_IDLE then false
|
|
195
|
+
end
|
|
196
|
+
rescue ::PG::ConnectionBad
|
|
197
|
+
false
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License").
|
|
6
|
+
# You may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
17
|
+
module AwsAdvancedRubyDriverWrapper
|
|
18
|
+
module Errors
|
|
19
|
+
module ErrorHandler
|
|
20
|
+
def network_error?(error)
|
|
21
|
+
check_cause_chain(error) { |sql_state, _| network_error_by_sql_state?(sql_state) }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def network_error_by_sql_state?(sql_state)
|
|
25
|
+
raise NotImplementedError
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def login_error?(error)
|
|
29
|
+
check_cause_chain(error) { |sql_state, _| login_error_by_sql_state?(sql_state) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def login_error_by_sql_state?(sql_state)
|
|
33
|
+
raise NotImplementedError
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def read_only_error?(error)
|
|
37
|
+
check_cause_chain(error) { |sql_state, _| read_only_error_by_sql_state?(sql_state) }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def read_only_error_by_sql_state?(sql_state, error_code = nil)
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def extract_sql_state(error)
|
|
47
|
+
@driver_dialect.sql_state(error)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def check_cause_chain(error)
|
|
51
|
+
current = error
|
|
52
|
+
while current
|
|
53
|
+
sql_state = extract_sql_state(current)
|
|
54
|
+
return true if yield(sql_state, current)
|
|
55
|
+
|
|
56
|
+
current = current.cause
|
|
57
|
+
end
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|