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.
Files changed (150) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +23 -0
  3. data/LICENSE +175 -0
  4. data/NOTICE +1 -0
  5. data/README.md +168 -0
  6. data/THIRD-PARTY-LICENSES +473 -0
  7. data/aws_advanced_ruby_driver_wrapper.gemspec +73 -0
  8. data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_mysql2_adapter.rb +73 -0
  9. data/lib/aws_advanced_ruby_driver_wrapper/active_record/aws_postgresql_adapter.rb +95 -0
  10. data/lib/aws_advanced_ruby_driver_wrapper/custom_configuration.rb +58 -0
  11. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_mysql_dialect.rb +103 -0
  12. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/aurora_pg_dialect.rb +124 -0
  13. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/dialect_codes.rb +38 -0
  14. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_mysql_dialect.rb +91 -0
  15. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/global_pg_dialect.rb +92 -0
  16. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_mysql_dialect.rb +95 -0
  17. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/multi_az_cluster_pg_dialect.rb +86 -0
  18. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/mysql_dialect.rb +98 -0
  19. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/pg_dialect.rb +95 -0
  20. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_mysql_dialect.rb +88 -0
  21. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/rds_pg_dialect.rb +86 -0
  22. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/unknown_dialect.rb +72 -0
  23. data/lib/aws_advanced_ruby_driver_wrapper/db_dialects/utils/dialect_utils.rb +71 -0
  24. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect.rb +154 -0
  25. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/driver_dialect_manager.rb +55 -0
  26. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/mysql_driver_dialect.rb +165 -0
  27. data/lib/aws_advanced_ruby_driver_wrapper/driver_dialects/pg_driver_dialect.rb +201 -0
  28. data/lib/aws_advanced_ruby_driver_wrapper/errors/error_handler.rb +62 -0
  29. data/lib/aws_advanced_ruby_driver_wrapper/errors/mysql_error_handler.rb +80 -0
  30. data/lib/aws_advanced_ruby_driver_wrapper/errors/pg_error_handler.rb +126 -0
  31. data/lib/aws_advanced_ruby_driver_wrapper/errors.rb +59 -0
  32. data/lib/aws_advanced_ruby_driver_wrapper/host/connection_string_host_list_provider.rb +95 -0
  33. data/lib/aws_advanced_ruby_driver_wrapper/host/global_aurora_host_list_provider.rb +65 -0
  34. data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability.rb +24 -0
  35. data/lib/aws_advanced_ruby_driver_wrapper/host/host_availability_strategy.rb +27 -0
  36. data/lib/aws_advanced_ruby_driver_wrapper/host/host_info.rb +137 -0
  37. data/lib/aws_advanced_ruby_driver_wrapper/host/host_role.rb +25 -0
  38. data/lib/aws_advanced_ruby_driver_wrapper/host/random_host_selector.rb +40 -0
  39. data/lib/aws_advanced_ruby_driver_wrapper/host/rds_host_list_provider.rb +206 -0
  40. data/lib/aws_advanced_ruby_driver_wrapper/logging.rb +110 -0
  41. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/cluster_topology_monitor.rb +709 -0
  42. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/global_cluster_topology_monitor.rb +72 -0
  43. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor.rb +99 -0
  44. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_connection.rb +57 -0
  45. data/lib/aws_advanced_ruby_driver_wrapper/monitoring/monitor_state.rb +25 -0
  46. data/lib/aws_advanced_ruby_driver_wrapper/mysql.rb +429 -0
  47. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/blue_green_plugin.rb +205 -0
  48. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/host_mapper.rb +132 -0
  49. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/iam_host_tracker.rb +84 -0
  50. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interim_status.rb +92 -0
  51. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/interval_rate.rb +27 -0
  52. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase.rb +69 -0
  53. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_event_log.rb +85 -0
  54. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/phase_time_info.rb +25 -0
  55. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/role.rb +38 -0
  56. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/base_routing.rb +83 -0
  57. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/reject_connect_routing.rb +40 -0
  58. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/substitute_connect_routing.rb +136 -0
  59. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_connect_routing.rb +53 -0
  60. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_execute_routing.rb +52 -0
  61. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/routing/suspend_until_corresponding_host_found_connect_routing.rb +83 -0
  62. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status.rb +68 -0
  63. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_builder.rb +244 -0
  64. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_info.rb +30 -0
  65. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_monitor.rb +564 -0
  66. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/status_provider.rb +414 -0
  67. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_state.rb +98 -0
  68. data/lib/aws_advanced_ruby_driver_wrapper/plugins/blue_green/switchover_timer.rb +46 -0
  69. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_monitor.rb +266 -0
  70. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/custom_endpoint_plugin.rb +158 -0
  71. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/info.rb +111 -0
  72. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/member_list_type.rb +31 -0
  73. data/lib/aws_advanced_ruby_driver_wrapper/plugins/custom_endpoint/role.rb +45 -0
  74. data/lib/aws_advanced_ruby_driver_wrapper/plugins/default_plugin.rb +108 -0
  75. data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_mode.rb +43 -0
  76. data/lib/aws_advanced_ruby_driver_wrapper/plugins/failover_plugin.rb +467 -0
  77. data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_mode.rb +68 -0
  78. data/lib/aws_advanced_ruby_driver_wrapper/plugins/gdb/gdb_failover_plugin.rb +403 -0
  79. data/lib/aws_advanced_ruby_driver_wrapper/plugins/iam_auth_plugin.rb +159 -0
  80. data/lib/aws_advanced_ruby_driver_wrapper/plugins/initial_connection_strategy_plugin.rb +485 -0
  81. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/audit_logger.rb +157 -0
  82. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_cipher.rb +159 -0
  83. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/column_encryption_config.rb +61 -0
  84. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/connection_source.rb +91 -0
  85. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/data_key_cache.rb +220 -0
  86. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_algorithm.rb +75 -0
  87. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_config.rb +146 -0
  88. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/encryption_service.rb +391 -0
  89. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/error_context.rb +198 -0
  90. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/errors.rb +259 -0
  91. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_management_utility.rb +435 -0
  92. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_manager.rb +378 -0
  93. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/key_metadata.rb +86 -0
  94. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_plugin.rb +890 -0
  95. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/kms_encryption_utility.rb +281 -0
  96. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/metadata_manager.rb +332 -0
  97. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sanitizer.rb +147 -0
  98. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_name.rb +70 -0
  99. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/schema_validator.rb +211 -0
  100. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/sql_runner.rb +147 -0
  101. data/lib/aws_advanced_ruby_driver_wrapper/plugins/kms_encryption/type_marker.rb +109 -0
  102. data/lib/aws_advanced_ruby_driver_wrapper/plugins/secrets_manager_plugin.rb +358 -0
  103. data/lib/aws_advanced_ruby_driver_wrapper/postgresql.rb +659 -0
  104. data/lib/aws_advanced_ruby_driver_wrapper/property_definition.rb +409 -0
  105. data/lib/aws_advanced_ruby_driver_wrapper/ruby_method.rb +122 -0
  106. data/lib/aws_advanced_ruby_driver_wrapper/services/connection_service.rb +143 -0
  107. data/lib/aws_advanced_ruby_driver_wrapper/services/dialect_service.rb +267 -0
  108. data/lib/aws_advanced_ruby_driver_wrapper/services/host_service.rb +199 -0
  109. data/lib/aws_advanced_ruby_driver_wrapper/services/monitor_service.rb +186 -0
  110. data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_call_context.rb +63 -0
  111. data/lib/aws_advanced_ruby_driver_wrapper/services/plugin_manager.rb +273 -0
  112. data/lib/aws_advanced_ruby_driver_wrapper/services/service_container.rb +30 -0
  113. data/lib/aws_advanced_ruby_driver_wrapper/services/service_utility.rb +78 -0
  114. data/lib/aws_advanced_ruby_driver_wrapper/services/session_state_service.rb +56 -0
  115. data/lib/aws_advanced_ruby_driver_wrapper/utils/accessible_regions.rb +52 -0
  116. data/lib/aws_advanced_ruby_driver_wrapper/utils/ar_constants.rb +25 -0
  117. data/lib/aws_advanced_ruby_driver_wrapper/utils/aurora_topology_utils.rb +99 -0
  118. data/lib/aws_advanced_ruby_driver_wrapper/utils/aws_credentials_utils.rb +62 -0
  119. data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config.rb +91 -0
  120. data/lib/aws_advanced_ruby_driver_wrapper/utils/connection_config_parser.rb +368 -0
  121. data/lib/aws_advanced_ruby_driver_wrapper/utils/conversion_utils.rb +51 -0
  122. data/lib/aws_advanced_ruby_driver_wrapper/utils/events/batching_event_publisher.rb +119 -0
  123. data/lib/aws_advanced_ruby_driver_wrapper/utils/events/data_access_event.rb +26 -0
  124. data/lib/aws_advanced_ruby_driver_wrapper/utils/events/monitor_reset_event.rb +26 -0
  125. data/lib/aws_advanced_ruby_driver_wrapper/utils/global_aurora_topology_utils.rb +185 -0
  126. data/lib/aws_advanced_ruby_driver_wrapper/utils/host_list_utils.rb +27 -0
  127. data/lib/aws_advanced_ruby_driver_wrapper/utils/iam_auth_utils.rb +112 -0
  128. data/lib/aws_advanced_ruby_driver_wrapper/utils/multi_az_topology_utils.rb +117 -0
  129. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/encryption_annotation_parser.rb +99 -0
  130. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/mysql_statement_analyzer.rb +641 -0
  131. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/pg_statement_analyzer.rb +502 -0
  132. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_analysis.rb +63 -0
  133. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/query_type.rb +35 -0
  134. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint.rb +27 -0
  135. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/routing_hint_parser.rb +50 -0
  136. data/lib/aws_advanced_ruby_driver_wrapper/utils/parser/sql_parser.rb +139 -0
  137. data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_url_type.rb +71 -0
  138. data/lib/aws_advanced_ruby_driver_wrapper/utils/rds_utils.rb +575 -0
  139. data/lib/aws_advanced_ruby_driver_wrapper/utils/retry_util.rb +153 -0
  140. data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_encoding.rb +56 -0
  141. data/lib/aws_advanced_ruby_driver_wrapper/utils/sql_method_analyzer.rb +195 -0
  142. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/cache_entry.rb +56 -0
  143. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/expiration_cache.rb +108 -0
  144. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/sliding_expiration_cache.rb +137 -0
  145. data/lib/aws_advanced_ruby_driver_wrapper/utils/storage/storage_service.rb +172 -0
  146. data/lib/aws_advanced_ruby_driver_wrapper/utils/topology_utils.rb +127 -0
  147. data/lib/aws_advanced_ruby_driver_wrapper/version.rb +19 -0
  148. data/lib/aws_advanced_ruby_driver_wrapper/wrapper_property.rb +64 -0
  149. data/lib/aws_advanced_ruby_driver_wrapper.rb +116 -0
  150. metadata +227 -0
@@ -0,0 +1,409 @@
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 'wrapper_property'
18
+
19
+ module AwsAdvancedRubyDriverWrapper
20
+ module PropertyDefinition
21
+ POSITIVE_INTEGER = lambda do |val, name|
22
+ raise ArgumentError, "#{name} must be a positive integer, got: #{val.inspect}" unless val&.to_i&.positive?
23
+ end
24
+
25
+ NON_NEGATIVE_INTEGER = lambda do |val, name|
26
+ raise ArgumentError, "#{name} must be a non-negative integer, got: #{val.inspect}" if val&.to_i&.negative?
27
+ end
28
+
29
+ POSITIVE_FLOAT = lambda do |val, name|
30
+ raise ArgumentError, "#{name} must be a positive number, got: #{val.inspect}" unless val&.to_f&.positive?
31
+ end
32
+
33
+ NON_NEGATIVE_FLOAT = lambda do |val, name|
34
+ raise ArgumentError, "#{name} must be a non-negative number, got: #{val.inspect}" if val&.to_f&.negative?
35
+ end
36
+
37
+ # Upper bound for the IAM token cache TTL. An RDS IAM auth token is only valid for 15 minutes
38
+ # (900s), so the cache must expire strictly before then to guarantee a cached token is never
39
+ # reused past its lifetime.
40
+ IAM_MAX_EXPIRATION_SEC = 870.0
41
+
42
+ IAM_EXPIRATION_SEC_BOUND = lambda do |val, name|
43
+ f = val&.to_f
44
+ unless f&.positive? && f <= IAM_MAX_EXPIRATION_SEC
45
+ raise ArgumentError,
46
+ "#{name} must be greater than 0 and at most #{IAM_MAX_EXPIRATION_SEC} seconds " \
47
+ "(the maximum keeps the IAM token cache below its 15-minute validity), got: #{val.inspect}"
48
+ end
49
+ end
50
+
51
+ # -- General --
52
+ CLUSTER_ID = WrapperProperty.new(:cluster_id, 'Unique identifier for the database cluster', default_value: '1', type: String)
53
+ PLUGINS = WrapperProperty.new(:wrapper_plugins, 'Comma-separated list of plugin codes', default_value: 'failover,initial_connection',
54
+ type: String)
55
+ DIALECT = WrapperProperty.new(:wrapper_dialect, 'The database dialect identifier for the database in use.', type: String)
56
+ AWS_CREDENTIALS_PROVIDER = WrapperProperty.new(:aws_credentials_provider,
57
+ 'AWS credentials provider for IAM token generation or Secrets Manager',
58
+ default_value: nil)
59
+ # -- Failover --
60
+ FAILOVER_TIMEOUT_SEC = WrapperProperty.new(
61
+ :failover_timeout_sec,
62
+ 'Maximum allowed time in seconds for the failover process.',
63
+ default_value: 300.0,
64
+ type: Float,
65
+ validator: POSITIVE_FLOAT
66
+ )
67
+ FAILOVER_MODE = WrapperProperty.new(
68
+ :failover_mode,
69
+ 'Set the desired instance role to target during failover.',
70
+ default_value: nil,
71
+ type: String
72
+ )
73
+ FAILOVER_READER_HOST_SELECTOR_STRATEGY = WrapperProperty.new(
74
+ :failover_reader_host_selector_strategy,
75
+ 'The strategy that should be used to select a new reader host while opening a new connection.',
76
+ default_value: 'random',
77
+ type: String
78
+ )
79
+ ENABLE_CONNECT_FAILOVER = WrapperProperty.new(
80
+ :enable_connect_failover,
81
+ 'Enable/disable cluster-aware failover if the initial connection fails due to a network exception.',
82
+ default_value: false,
83
+ type: :boolean
84
+ )
85
+
86
+ # -- GDB Failover --
87
+ IN_HOME_FAILOVER_MODE = WrapperProperty.new(
88
+ :in_home_failover_mode,
89
+ 'GDB-only: the host role to target during failover while the GDB primary region is the home region. ' \
90
+ 'Valid values are strict_writer, strict_home_reader, strict_out_of_home_reader, strict_any_reader, ' \
91
+ 'home_reader_or_writer, out_of_home_reader_or_writer, and any_reader_or_writer.',
92
+ default_value: nil,
93
+ type: String
94
+ )
95
+ OUT_OF_HOME_FAILOVER_MODE = WrapperProperty.new(
96
+ :out_of_home_failover_mode,
97
+ 'GDB-only: the host role to target during failover while the GDB primary region is not the home region. ' \
98
+ 'Accepts the same values as in_home_failover_mode.',
99
+ default_value: nil,
100
+ type: String
101
+ )
102
+ FAILOVER_HOME_REGION = WrapperProperty.new(
103
+ :failover_home_region,
104
+ 'GDB-only: the AWS region the application runs in, e.g. us-east-1. Determines which of ' \
105
+ 'in_home_failover_mode and out_of_home_failover_mode applies: the in-home mode is used while the GDB ' \
106
+ 'primary is in this region, and the out-of-home mode is used while it is not. Defaults to the region ' \
107
+ 'parsed from the connection endpoint, and is required when the endpoint carries no region, e.g. a global ' \
108
+ 'endpoint, an IP address, or a custom domain.',
109
+ default_value: nil,
110
+ type: String
111
+ )
112
+
113
+ # -- Topology Monitoring --
114
+ CLUSTER_INSTANCE_HOST_PATTERN = WrapperProperty.new(
115
+ :cluster_instance_host_pattern,
116
+ 'Instance endpoint pattern with ? placeholder. Required for IP/custom domain connections.',
117
+ default_value: nil,
118
+ type: String
119
+ )
120
+ GLOBAL_CLUSTER_INSTANCE_HOST_PATTERNS = WrapperProperty.new(
121
+ :global_cluster_instance_host_patterns,
122
+ 'Comma-separated list of region-prefixed instance patterns for Global Aurora Databases.',
123
+ default_value: nil,
124
+ type: String
125
+ )
126
+ CLUSTER_TOPOLOGY_REFRESH_RATE_SEC = WrapperProperty.new(
127
+ :cluster_topology_refresh_rate_sec,
128
+ 'Cluster topology refresh rate in seconds',
129
+ default_value: 5.0,
130
+ type: Float,
131
+ validator: POSITIVE_FLOAT
132
+ )
133
+ CLUSTER_TOPOLOGY_HIGH_REFRESH_RATE_SEC = WrapperProperty.new(
134
+ :cluster_topology_high_refresh_rate_sec,
135
+ 'Cluster topology high refresh rate in seconds (used post-failover)',
136
+ default_value: 0.1,
137
+ type: Float,
138
+ validator: POSITIVE_FLOAT
139
+ )
140
+ CLUSTER_TOPOLOGY_MAX_INSTANCE_MONITORS = WrapperProperty.new(
141
+ :cluster_topology_max_instance_monitors,
142
+ 'Maximum number of parallel instance monitors during topology updates',
143
+ default_value: 16,
144
+ type: Integer
145
+ )
146
+
147
+ # -- Blue/Green --
148
+ BGD_ID = WrapperProperty.new(:bgd_id, 'Blue/Green Deployment identifier that helps the driver to distinguish different deployments.',
149
+ default_value: '1', type: String)
150
+ BG_CONNECT_TIMEOUT_SEC = WrapperProperty.new(:bg_connect_timeout_sec, 'Blue/Green connect timeout in seconds',
151
+ default_value: 30.0, type: Float, validator: POSITIVE_FLOAT)
152
+ BG_INTERVAL_BASELINE_SEC = WrapperProperty.new(:bg_baseline_sec,
153
+ 'Baseline Blue/Green Deployment status checking interval (in seconds).',
154
+ default_value: 60.0, type: Float, validator: POSITIVE_FLOAT)
155
+ BG_INTERVAL_INCREASED_SEC = WrapperProperty.new(:bg_increased_sec,
156
+ 'Increased Blue/Green Deployment status checking interval (in seconds).',
157
+ default_value: 1.0, type: Float, validator: POSITIVE_FLOAT)
158
+ BG_INTERVAL_HIGH_SEC = WrapperProperty.new(:bg_high_sec, 'High Blue/Green Deployment status checking interval (in seconds).',
159
+ default_value: 0.1, type: Float, validator: POSITIVE_FLOAT)
160
+ BG_SWITCHOVER_TIMEOUT_SEC = WrapperProperty.new(:bg_switchover_timeout_sec, 'Blue/Green Deployment switchover timeout (in seconds).',
161
+ default_value: 180.0, type: Float, validator: POSITIVE_FLOAT)
162
+
163
+ # -- IAM Authentication --
164
+ IAM_HOST = WrapperProperty.new(:iam_host, 'Overrides the host used to generate the IAM token', default_value: nil, type: String)
165
+ IAM_PORT = WrapperProperty.new(:iam_port, 'Overrides the port used to generate the IAM token', default_value: nil, type: Integer)
166
+ IAM_REGION = WrapperProperty.new(:iam_region, 'Overrides the AWS region used to generate the IAM token', default_value: nil,
167
+ type: String)
168
+ IAM_EXPIRATION_SEC = WrapperProperty.new(:iam_expiration_sec,
169
+ 'IAM token cache expiration in seconds.',
170
+ default_value: IAM_MAX_EXPIRATION_SEC, type: Float, validator: IAM_EXPIRATION_SEC_BOUND)
171
+ IAM_ACCESS_TOKEN_PROPERTY_NAME = WrapperProperty.new(:iam_access_token_property_name, 'Property name used to pass the IAM token',
172
+ default_value: :password, type: Symbol)
173
+
174
+ # -- Initial Connection Strategy --
175
+ INITIAL_CONNECTION_SUBSTITUTE_HOST = WrapperProperty.new(
176
+ :initial_connection_substitute_host,
177
+ 'Role to substitute the endpoint with: writer, reader, any, or none. Auto-detects from endpoint type when not set.',
178
+ default_value: nil, type: String
179
+ )
180
+ INITIAL_CONNECTION_VERIFY_ROLE = WrapperProperty.new(
181
+ :initial_connection_verify_role,
182
+ 'Role to verify after connecting: writer, reader, or none. Auto-detects from endpoint type when not set.',
183
+ default_value: nil, type: String
184
+ )
185
+ INITIAL_CONNECTION_HOST_SELECTOR_STRATEGY = WrapperProperty.new(
186
+ :initial_connection_host_selector_strategy,
187
+ 'Strategy name for selecting a host when multiple match the substitution role.',
188
+ default_value: 'random', type: String
189
+ )
190
+ INITIAL_CONNECTION_RETRY_TIMEOUT_SEC = WrapperProperty.new(
191
+ :initial_connection_retry_timeout_sec,
192
+ 'Maximum time in seconds to retry opening a connection.',
193
+ default_value: 30.0, type: Float, validator: POSITIVE_FLOAT
194
+ )
195
+ INITIAL_CONNECTION_RETRY_INTERVAL_SEC = WrapperProperty.new(
196
+ :initial_connection_retry_interval_sec,
197
+ 'Time in seconds between retries when opening a connection.',
198
+ default_value: 1.0, type: Float, validator: POSITIVE_FLOAT
199
+ )
200
+ INITIAL_CONNECTION_WAIT_FOR_TOPOLOGY_SEC = WrapperProperty.new(
201
+ :initial_connection_wait_for_topology_sec,
202
+ 'Maximum allowed time, in seconds, to wait for the cluster topology to be fetched before opening a new ' \
203
+ 'connection. When set to a value greater than 0 and the topology is not yet available, the plugin ' \
204
+ 'will block until the topology has been discovered (or this timeout is reached) instead of falling ' \
205
+ 'back to connecting via the initial endpoint in the connection string.',
206
+ default_value: 0.0, type: Float, validator: NON_NEGATIVE_FLOAT
207
+ )
208
+ INITIAL_CONNECTION_INACTIVE_SUBSTITUTE_HOST = WrapperProperty.new(
209
+ :initial_connection_inactive_substitute_host,
210
+ 'GDB-only: substitution role for inactive cluster writer endpoints. Valid values are writer or ' \
211
+ 'none. When unset, the endpoint is passed through without substitution.',
212
+ default_value: nil, type: String
213
+ )
214
+ INITIAL_CONNECTION_INACTIVE_VERIFY_ROLE = WrapperProperty.new(
215
+ :initial_connection_inactive_verify_role,
216
+ 'GDB-only: verification role for inactive cluster writer endpoints. Valid values are writer or ' \
217
+ 'none. When unset, no role verification is performed unless a writer was substituted.',
218
+ default_value: nil, type: String
219
+ )
220
+ ACCESSIBLE_REGIONS = WrapperProperty.new(
221
+ :accessible_regions,
222
+ 'Comma-separated list of AWS regions accessible by the application. All regions allowed when not set.',
223
+ default_value: nil, type: String
224
+ )
225
+
226
+ # -- Custom Endpoint --
227
+ CUSTOM_ENDPOINT_INFO_REFRESH_RATE_SEC = WrapperProperty.new(
228
+ :custom_endpoint_info_refresh_rate_sec,
229
+ 'How frequently custom endpoint monitors fetch custom endpoint info, in seconds.',
230
+ default_value: 30.0,
231
+ type: Float,
232
+ validator: POSITIVE_FLOAT
233
+ )
234
+ CUSTOM_ENDPOINT_INFO_REFRESH_RATE_BACKOFF_FACTOR = WrapperProperty.new(
235
+ :custom_endpoint_info_refresh_rate_backoff_factor,
236
+ 'Exponential backoff factor for the custom endpoint monitor on throttling.',
237
+ default_value: 2,
238
+ type: Integer
239
+ )
240
+ CUSTOM_ENDPOINT_INFO_MAX_REFRESH_RATE_SEC = WrapperProperty.new(
241
+ :custom_endpoint_info_max_refresh_rate_sec,
242
+ 'Maximum wait between custom endpoint info fetches, in seconds.',
243
+ default_value: 300.0,
244
+ type: Float,
245
+ validator: POSITIVE_FLOAT
246
+ )
247
+ WAIT_FOR_CUSTOM_ENDPOINT_INFO = WrapperProperty.new(
248
+ :wait_for_custom_endpoint_info,
249
+ 'Controls whether to wait for custom endpoint info to become available before connecting or executing a ' \
250
+ 'method. Waiting is only necessary if a connection to a given custom endpoint has not been opened or used ' \
251
+ 'recently. Note that disabling this may result in occasional connections to instances outside of the ' \
252
+ 'custom endpoint.',
253
+ default_value: true,
254
+ type: :boolean
255
+ )
256
+ WAIT_FOR_CUSTOM_ENDPOINT_INFO_TIMEOUT_SEC = WrapperProperty.new(
257
+ :wait_for_custom_endpoint_info_timeout_sec,
258
+ 'Maximum time to wait for custom endpoint info, in seconds.',
259
+ default_value: 5.0,
260
+ type: Float,
261
+ validator: POSITIVE_FLOAT
262
+ )
263
+ CUSTOM_ENDPOINT_MONITOR_EXPIRATION_SEC = WrapperProperty.new(
264
+ :custom_endpoint_monitor_expiration_sec,
265
+ 'How long a monitor runs without use before expiring, in seconds.',
266
+ default_value: 900.0,
267
+ type: Float,
268
+ validator: POSITIVE_FLOAT
269
+ )
270
+ CUSTOM_ENDPOINT_REGION = WrapperProperty.new(
271
+ :custom_endpoint_region,
272
+ 'Region of the custom endpoint. Parsed from the URL when not specified.',
273
+ default_value: nil,
274
+ type: String
275
+ )
276
+
277
+ # -- Secrets Manager --
278
+ SECRET_ID = WrapperProperty.new(
279
+ :secret_id, 'The name or ARN of the secret to retrieve', default_value: nil, type: String
280
+ )
281
+ SECRET_REGION = WrapperProperty.new(
282
+ :secret_region, 'AWS region for Secrets Manager API calls', default_value: nil, type: String
283
+ )
284
+ SECRET_ENDPOINT = WrapperProperty.new(
285
+ :secret_endpoint, 'Custom endpoint URL for Secrets Manager', default_value: nil, type: String
286
+ )
287
+ SECRET_USERNAME_KEY = WrapperProperty.new(
288
+ :secret_username_key, 'JSON key containing the username in the secret',
289
+ default_value: 'username', type: String
290
+ )
291
+ SECRET_PASSWORD_KEY = WrapperProperty.new(
292
+ :secret_password_key, 'JSON key containing the password in the secret',
293
+ default_value: 'password', type: String
294
+ )
295
+ SECRET_EXPIRATION_SEC = WrapperProperty.new(
296
+ :secret_expiration_sec, 'Cached secret expiration in seconds (minimum: 300)',
297
+ default_value: 870.0, type: Float, validator: POSITIVE_FLOAT
298
+ )
299
+ SECRET_ROTATION_RETRY_TIMEOUT_SEC = WrapperProperty.new(
300
+ :secret_rotation_retry_timeout_sec,
301
+ 'Max time in seconds to retry connecting during a secret rotation window (0 = disabled)',
302
+ default_value: 0.0, type: Float, validator: NON_NEGATIVE_FLOAT
303
+ )
304
+ SECRET_ROTATION_RETRY_BASE_DELAY_SEC = WrapperProperty.new(
305
+ :secret_rotation_retry_base_delay_sec,
306
+ 'Base delay in seconds for exponential backoff during rotation retry',
307
+ default_value: 0.5, type: Float, validator: POSITIVE_FLOAT
308
+ )
309
+
310
+ # -- KMS Encryption --
311
+ ENCRYPTION_KMS_REGION = WrapperProperty.new(
312
+ :encryption_kms_region,
313
+ 'AWS region for KMS calls made by the kms_encryption plugin. Required: falls back to the ' \
314
+ 'AWS_REGION or AWS_DEFAULT_REGION environment variable, and is rejected if none is set.',
315
+ default_value: nil, type: String
316
+ )
317
+ ENCRYPTION_KMS_ENDPOINT = WrapperProperty.new(
318
+ :encryption_kms_endpoint, 'Custom endpoint URL for KMS', default_value: nil, type: String
319
+ )
320
+ ENCRYPTION_ALLOWED_MASTER_KEY_ARNS = WrapperProperty.new(
321
+ :encryption_allowed_master_key_arns,
322
+ 'The KMS master keys the kms_encryption plugin may use, as a comma-separated string or an array. ' \
323
+ 'Required by the plugin. Each entry must match a key_storage.master_key_arn value exactly; a stored ' \
324
+ 'data key that names any other master key (or none) is refused before KMS is called.',
325
+ default_value: nil
326
+ )
327
+ ENCRYPTION_METADATA_SCHEMA = WrapperProperty.new(
328
+ :encryption_metadata_schema,
329
+ 'Schema holding the encryption_metadata and key_storage tables',
330
+ default_value: 'encrypt', type: String
331
+ )
332
+ ENCRYPTION_METADATA_CACHE_ENABLED = WrapperProperty.new(
333
+ :encryption_metadata_cache_enabled,
334
+ 'Cache the kms_encryption metadata in memory instead of querying it per statement',
335
+ default_value: true, type: :boolean
336
+ )
337
+ ENCRYPTION_METADATA_CACHE_EXPIRATION_SEC = WrapperProperty.new(
338
+ :encryption_metadata_cache_expiration_sec,
339
+ 'How long cached kms_encryption metadata stays valid, in seconds',
340
+ default_value: 3600.0, type: Float, validator: POSITIVE_FLOAT
341
+ )
342
+ ENCRYPTION_METADATA_CACHE_REFRESH_INTERVAL_SEC = WrapperProperty.new(
343
+ :encryption_metadata_cache_refresh_interval_sec,
344
+ 'How often the kms_encryption metadata is refreshed in the background, in seconds (0 disables background refresh)',
345
+ default_value: 300.0, type: Float, validator: NON_NEGATIVE_FLOAT
346
+ )
347
+ ENCRYPTION_KEY_MANAGEMENT_MAX_RETRIES = WrapperProperty.new(
348
+ :encryption_key_management_max_retries,
349
+ 'Maximum number of retries for throttled or failed KMS calls',
350
+ default_value: 3, type: Integer, validator: NON_NEGATIVE_INTEGER
351
+ )
352
+ ENCRYPTION_KEY_MANAGEMENT_RETRY_BACKOFF_BASE_SEC = WrapperProperty.new(
353
+ :encryption_key_management_retry_backoff_base_sec,
354
+ 'Base delay in seconds for the exponential backoff between KMS retries',
355
+ default_value: 0.1, type: Float, validator: POSITIVE_FLOAT
356
+ )
357
+ ENCRYPTION_AUDIT_LOGGING_ENABLED = WrapperProperty.new(
358
+ :encryption_audit_logging_enabled,
359
+ 'Log an audit record for every key management, kms_encryption, and decryption operation',
360
+ default_value: false, type: :boolean
361
+ )
362
+ ENCRYPTION_RETURN_UNVERIFIED_DATA = WrapperProperty.new(
363
+ :encryption_return_unverified_data,
364
+ 'On read, return a value as it is stored when it cannot be confirmed to be valid encrypted data ' \
365
+ '(too short to be a payload, or a failed HMAC) instead of raising. Intended only for reading data ' \
366
+ 'written before kms_encryption was enabled. MUST NOT be enabled in production: it lets unverified ' \
367
+ 'data reach the application. A value that verifies but cannot be decrypted still raises.',
368
+ default_value: false, type: :boolean
369
+ )
370
+ ENCRYPTION_DATA_KEY_CACHE_ENABLED = WrapperProperty.new(
371
+ :encryption_data_key_cache_enabled,
372
+ 'Cache decrypted data keys in memory to avoid a KMS Decrypt call per statement',
373
+ default_value: true, type: :boolean
374
+ )
375
+ ENCRYPTION_DATA_KEY_CACHE_MAX_SIZE = WrapperProperty.new(
376
+ :encryption_data_key_cache_max_size,
377
+ 'Maximum number of decrypted data keys held in memory',
378
+ default_value: 1000, type: Integer, validator: POSITIVE_INTEGER
379
+ )
380
+ ENCRYPTION_DATA_KEY_CACHE_EXPIRATION_SEC = WrapperProperty.new(
381
+ :encryption_data_key_cache_expiration_sec,
382
+ 'How long a decrypted data key stays cached, in seconds',
383
+ default_value: 300.0, type: Float, validator: POSITIVE_FLOAT
384
+ )
385
+
386
+ # Built once at load time from constants — used by parser to split props
387
+ KNOWN_PROPERTIES = constants
388
+ .filter_map { |c| const_get(c) if const_get(c).is_a?(WrapperProperty) }
389
+ .to_h { |prop| [prop.name, prop] }
390
+ .freeze
391
+
392
+ # Known prefixes for internal connection overrides. Each prefix maps to a key
393
+ # used in ConnectionConfig#prefixed_wrapper_config and ConnectionConfig#prefixed_driver_config.
394
+ # Plugins define their own prefix here.
395
+ TOPOLOGY_MONITORING_PREFIX = 'topology_monitoring_'
396
+ BG_MONITORING_PROPERTY_PREFIX = 'bg_monitoring_'
397
+
398
+ KNOWN_PREFIXES = [
399
+ TOPOLOGY_MONITORING_PREFIX,
400
+ BG_MONITORING_PROPERTY_PREFIX
401
+ ].freeze
402
+
403
+ BG_STORAGE_NAMESPACE = '941d00a8-8238-4f7d-bf59-771bff783a8e'
404
+
405
+ def self.wrapper_property?(key)
406
+ KNOWN_PROPERTIES.key?(key.to_sym)
407
+ end
408
+ end
409
+ end
@@ -0,0 +1,122 @@
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
+ MethodInfo = Data.define(:name, :check_bounded_connection) do
19
+ def to_s
20
+ name
21
+ end
22
+ end
23
+
24
+ module RubyMethod
25
+ def self.define(name, check_bounded_connection:)
26
+ MethodInfo.new(name:, check_bounded_connection:)
27
+ end
28
+
29
+ # -- Internal pipeline methods --
30
+ CONNECT = define('connect', check_bounded_connection: false)
31
+
32
+ # -- Connection methods --
33
+ CONNECTION_CLOSE = define('connection.close', check_bounded_connection: false)
34
+ CONNECTION_RESET = define('connection.reset', check_bounded_connection: false)
35
+ CONNECTION_PREPARE = define('connection.prepare', check_bounded_connection: false)
36
+ CONNECTION_ESCAPE = define('connection.escape', check_bounded_connection: false)
37
+
38
+ # -- Connection methods (mysql2-specific) --
39
+ CONNECTION_PING = define('connection.ping', check_bounded_connection: false)
40
+ CONNECTION_QUERY = define('connection.query', check_bounded_connection: false)
41
+ CONNECTION_ASYNC_RESULT = define('connection.async_result', check_bounded_connection: true)
42
+ CONNECTION_SELECT_DB = define('connection.select_db', check_bounded_connection: false)
43
+ CONNECTION_MORE_RESULTS = define('connection.more_results?', check_bounded_connection: true)
44
+ CONNECTION_NEXT_RESULT = define('connection.next_result', check_bounded_connection: true)
45
+ CONNECTION_STORE_RESULT = define('connection.store_result', check_bounded_connection: true)
46
+ CONNECTION_ABANDON_RESULTS = define('connection.abandon_results!', check_bounded_connection: true)
47
+ CONNECTION_SET_SERVER_OPTION = define('connection.set_server_option', check_bounded_connection: false)
48
+
49
+ # -- Connection methods (pg-specific) --
50
+ CONNECTION_EXEC = define('connection.exec', check_bounded_connection: false)
51
+ CONNECTION_ASYNC_EXEC = define('connection.async_exec', check_bounded_connection: false)
52
+ CONNECTION_EXEC_PARAMS = define('connection.exec_params', check_bounded_connection: false)
53
+ CONNECTION_EXEC_PREPARED = define('connection.exec_prepared', check_bounded_connection: true)
54
+ CONNECTION_DESCRIBE_PREPARED = define('connection.describe_prepared', check_bounded_connection: true)
55
+ CONNECTION_DESCRIBE_PORTAL = define('connection.describe_portal', check_bounded_connection: true)
56
+ CONNECTION_TRANSACTION = define('connection.transaction', check_bounded_connection: false)
57
+ CONNECTION_COPY_DATA = define('connection.copy_data', check_bounded_connection: false)
58
+ CONNECTION_PUT_COPY_DATA = define('connection.put_copy_data', check_bounded_connection: true)
59
+ CONNECTION_GET_COPY_DATA = define('connection.get_copy_data', check_bounded_connection: true)
60
+ CONNECTION_PUT_COPY_END = define('connection.put_copy_end', check_bounded_connection: true)
61
+ CONNECTION_SEND_QUERY = define('connection.send_query', check_bounded_connection: false)
62
+ CONNECTION_SEND_QUERY_PARAMS = define('connection.send_query_params', check_bounded_connection: false)
63
+ CONNECTION_SEND_QUERY_PREPARED = define('connection.send_query_prepared', check_bounded_connection: true)
64
+ CONNECTION_SEND_PREPARE = define('connection.send_prepare', check_bounded_connection: false)
65
+ CONNECTION_GET_RESULT = define('connection.get_result', check_bounded_connection: true)
66
+ CONNECTION_GET_LAST_RESULT = define('connection.get_last_result', check_bounded_connection: true)
67
+ CONNECTION_CANCEL = define('connection.cancel', check_bounded_connection: false)
68
+ CONNECTION_SET_CLIENT_ENCODING = define('connection.set_client_encoding', check_bounded_connection: false)
69
+ CONNECTION_WAIT_FOR_NOTIFY = define('connection.wait_for_notify', check_bounded_connection: false)
70
+ CONNECTION_NOTIFIES = define('connection.notifies', check_bounded_connection: false)
71
+ CONNECTION_CONSUME_INPUT = define('connection.consume_input', check_bounded_connection: false)
72
+ CONNECTION_FLUSH = define('connection.flush', check_bounded_connection: false)
73
+ CONNECTION_LO_OPEN = define('connection.lo_open', check_bounded_connection: false)
74
+ CONNECTION_LO_READ = define('connection.lo_read', check_bounded_connection: true)
75
+ CONNECTION_LO_WRITE = define('connection.lo_write', check_bounded_connection: true)
76
+ CONNECTION_LO_CLOSE = define('connection.lo_close', check_bounded_connection: true)
77
+ CONNECTION_CLOSE_PREPARED = define('connection.close_prepared', check_bounded_connection: true)
78
+ CONNECTION_CLOSE_PORTAL = define('connection.close_portal', check_bounded_connection: true)
79
+ CONNECTION_DISCARD_RESULTS = define('connection.discard_results', check_bounded_connection: true)
80
+ CONNECTION_SEND_DESCRIBE_PREPARED = define('connection.send_describe_prepared', check_bounded_connection: true)
81
+ CONNECTION_SEND_DESCRIBE_PORTAL = define('connection.send_describe_portal', check_bounded_connection: true)
82
+ CONNECTION_SEND_FLUSH_REQUEST = define('connection.send_flush_request', check_bounded_connection: true)
83
+ CONNECTION_PIPELINE_SYNC = define('connection.pipeline_sync', check_bounded_connection: true)
84
+ CONNECTION_SEND_PIPELINE_SYNC = define('connection.send_pipeline_sync', check_bounded_connection: true)
85
+ CONNECTION_BLOCK = define('connection.block', check_bounded_connection: true)
86
+ CONNECTION_RESET_START = define('connection.reset_start', check_bounded_connection: false)
87
+ CONNECTION_RESET_POLL = define('connection.reset_poll', check_bounded_connection: false)
88
+ CONNECTION_ENCRYPT_PASSWORD = define('connection.encrypt_password', check_bounded_connection: false)
89
+ CONNECTION_SET_DEFAULT_ENCODING = define('connection.set_default_encoding', check_bounded_connection: false)
90
+ CONNECTION_INTERNAL_ENCODING_SET = define('connection.internal_encoding=', check_bounded_connection: false)
91
+ CONNECTION_LO_CREAT = define('connection.lo_creat', check_bounded_connection: false)
92
+ CONNECTION_LO_CREATE = define('connection.lo_create', check_bounded_connection: false)
93
+ CONNECTION_LO_IMPORT = define('connection.lo_import', check_bounded_connection: false)
94
+ CONNECTION_LO_EXPORT = define('connection.lo_export', check_bounded_connection: false)
95
+ CONNECTION_LO_UNLINK = define('connection.lo_unlink', check_bounded_connection: false)
96
+ CONNECTION_LO_LSEEK = define('connection.lo_lseek', check_bounded_connection: true)
97
+ CONNECTION_LO_TELL = define('connection.lo_tell', check_bounded_connection: true)
98
+ CONNECTION_LO_TRUNCATE = define('connection.lo_truncate', check_bounded_connection: true)
99
+
100
+ # -- Statement methods --
101
+ STATEMENT_EXECUTE = define('statement.execute', check_bounded_connection: true)
102
+ STATEMENT_CLOSE = define('statement.close', check_bounded_connection: false)
103
+
104
+ # -- Result methods --
105
+ RESULT_EACH = define('result.each', check_bounded_connection: true)
106
+ RESULT_EACH_ROW = define('result.each_row', check_bounded_connection: true)
107
+ RESULT_TO_A = define('result.to_a', check_bounded_connection: true)
108
+ RESULT_BRACKET = define('result.[]', check_bounded_connection: true)
109
+ RESULT_VALUES = define('result.values', check_bounded_connection: true)
110
+ RESULT_COLUMN_VALUES = define('result.column_values', check_bounded_connection: true)
111
+ RESULT_FIELD_VALUES = define('result.field_values', check_bounded_connection: true)
112
+ RESULT_TUPLE = define('result.tuple', check_bounded_connection: true)
113
+ RESULT_TUPLE_VALUES = define('result.tuple_values', check_bounded_connection: true)
114
+ RESULT_GETVALUE = define('result.getvalue', check_bounded_connection: true)
115
+ RESULT_STREAM_EACH = define('result.stream_each', check_bounded_connection: true)
116
+ RESULT_STREAM_EACH_ROW = define('result.stream_each_row', check_bounded_connection: true)
117
+ RESULT_STREAM_EACH_TUPLE = define('result.stream_each_tuple', check_bounded_connection: true)
118
+ # Freeing an unbuffered result has to read whatever rows are still on the wire before it can let
119
+ # the result go, so it is a call to the server on the connection the statement was sent on.
120
+ RESULT_FREE = define('result.free', check_bounded_connection: true)
121
+ end
122
+ end
@@ -0,0 +1,143 @@
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 'monitor'
18
+ require_relative '../utils/host_list_utils'
19
+
20
+ module AwsAdvancedRubyDriverWrapper
21
+ module Services
22
+ class ConnectionService
23
+ attr_reader :current_connection, :config
24
+
25
+ # @param config [Utils::ConnectionConfig] the parsed connection configuration
26
+ def initialize(service_container, config)
27
+ @service_container = service_container
28
+ @config = config
29
+ @current_connection = nil
30
+ @current_host_info = config.initial_host_info
31
+ @connection_switch_lock = Monitor.new
32
+ end
33
+
34
+ # @return [Host::HostInfo, nil] host info for the current connection
35
+ def current_host_info
36
+ return @current_host_info if @current_host_info
37
+
38
+ @current_host_info = @config.initial_host_info
39
+ return @current_host_info if @current_host_info
40
+
41
+ host_service = @service_container.host_service
42
+ hosts = host_service.all_hosts
43
+ raise Errors::AwsError, 'Attempted to access the current host list, but the host list is empty' if host_service.all_hosts.empty?
44
+
45
+ @current_host_info = Utils::HostListUtils.writer(hosts)
46
+ allowed_hosts = host_service.hosts
47
+ if @current_host_info && !Utils::HostListUtils.contains_url?(allowed_hosts, @current_host_info.url)
48
+ raise Errors::AwsError,
49
+ 'Current host is not in the list of allowed hosts: ' \
50
+ "current_host=#{@current_host_info.url}, " \
51
+ "allowed_hosts=#{Utils::HostListUtils.to_host_urls_s(allowed_hosts)}"
52
+ end
53
+
54
+ @current_host_info = hosts[0] if @current_host_info.nil? && hosts.any?
55
+
56
+ if @current_host_info.nil?
57
+ raise Errors::AwsError,
58
+ 'Unable to identify a current host from the available host list'
59
+ end
60
+
61
+ @current_host_info
62
+ end
63
+
64
+ # @param connection [Object] the new connection
65
+ # @param host_info [Host::HostInfo] host info for the new connection
66
+ def update_current_connection(connection, host_info)
67
+ if connection.nil?
68
+ origin = caller(1, 5)
69
+ raise Errors::AwsError.new(
70
+ '[ConnectionService] update_current_connection called with nil connection! ' \
71
+ "host_info=#{host_info&.host}, caller=#{origin.join(' <- ')}",
72
+ connection_broken: true
73
+ )
74
+ end
75
+
76
+ @connection_switch_lock.synchronize do
77
+ # Close the connection being replaced so it does not leak.
78
+ previous = @current_connection
79
+ close_quietly(previous) unless previous.nil? || previous.equal?(connection)
80
+
81
+ @current_connection = connection
82
+ @current_host_info = host_info
83
+ @service_container.session_state_service.reset
84
+ end
85
+ end
86
+
87
+ # @return [Symbol] the driver name, e.g. :postgresql or :mysql2
88
+ def driver_name
89
+ @config.driver_name
90
+ end
91
+
92
+ # @return [Hash] wrapper-specific properties
93
+ def wrapper_props
94
+ @config.wrapper_props
95
+ end
96
+
97
+ # @return [Host::HostInfo, nil] the initial host info from config
98
+ def initial_host_info
99
+ @config.initial_host_info
100
+ end
101
+
102
+ def initial_host_info=(host_info)
103
+ @config.initial_host_info = host_info
104
+ end
105
+
106
+ # @return [Hash{String => Hash}] prefixed wrapper props keyed by prefix (already stripped)
107
+ def prefixed_wrapper_config
108
+ @config.prefixed_wrapper_config
109
+ end
110
+
111
+ # @return [Hash{String => Hash}] prefixed driver props keyed by prefix (already stripped)
112
+ def prefixed_driver_config
113
+ @config.prefixed_driver_config
114
+ end
115
+
116
+ # @return [Hash] driver-specific properties
117
+ def driver_props
118
+ @config.driver_props
119
+ end
120
+
121
+ # Whether the initial connection URL specified multiple hosts.
122
+ #
123
+ # @return [Boolean]
124
+ def multi_host_url?
125
+ @config.multi_host_url?
126
+ end
127
+
128
+ # @return [Boolean] whether the driver is PostgreSQL
129
+ def pg?
130
+ driver_name == :postgresql
131
+ end
132
+
133
+ private
134
+
135
+ # Closes a connection, ignoring any error. Used to release a connection that is being replaced.
136
+ def close_quietly(conn)
137
+ @service_container.dialect_service.driver_dialect.close_connection(conn)
138
+ rescue StandardError
139
+ nil
140
+ end
141
+ end
142
+ end
143
+ end