logstash-input-jdbc 4.3.14 → 4.3.16
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 +4 -4
 - data/CHANGELOG.md +11 -0
 - data/docs/index.asciidoc +57 -2
 - data/lib/logstash/inputs/jdbc.rb +37 -9
 - data/lib/logstash/plugin_mixins/jdbc/checked_count_logger.rb +8 -3
 - data/lib/logstash/plugin_mixins/jdbc/jdbc.rb +23 -55
 - data/lib/logstash/plugin_mixins/jdbc/statement_handler.rb +129 -0
 - data/lib/logstash/plugin_mixins/jdbc/value_tracking.rb +12 -13
 - data/logstash-input-jdbc.gemspec +1 -1
 - data/spec/inputs/jdbc_spec.rb +138 -0
 - metadata +3 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 05a9c38896f4f81325e5284a4cd46085105ecc31d5339526a67a42ff668d8c41
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: b8d46982d68047d258d0587f66e53cc324c419e8a97952b75db717894e453c24
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: b6ab529a8eac82086d7518a1cb282189c1ad96faf138637ab168889030f09c65a6159bfc0e79eaf8c2fff8806b0e71bec46dba15ba81fe08151ac3173953202b
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: e0071180f548ceac30f79b18e28b3804c29e559c873bf4a9d45bb11b61736f7a583fbc5a9e53b11d46ed58c3e3686e50de218db89535e231ba5a631cb0b3a941
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ## 4.3.16
         
     | 
| 
      
 2 
     | 
    
         
            +
              - Add support for prepared statements [Issue 233](https://github.com/logstash-plugins/logstash-input-jdbc/issues/233)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            ## 4.3.15
         
     | 
| 
      
 5 
     | 
    
         
            +
              - Use atomic booleam to load drivers once
         
     | 
| 
      
 6 
     | 
    
         
            +
              - Added CHANGELOG entries
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            ## 4.3.14
         
     | 
| 
      
 9 
     | 
    
         
            +
              - Added support for driver loading in JDK 9+ [Issue 331](https://github.com/logstash-plugins/logstash-input-jdbc/issues/331)
         
     | 
| 
      
 10 
     | 
    
         
            +
              - Gem released without CHANGELOG additions
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
       1 
12 
     | 
    
         
             
            ## 4.3.13
         
     | 
| 
       2 
13 
     | 
    
         
             
              - Changed documentation to generalize the PATH location [#297](https://github.com/logstash-plugins/logstash-input-jdbc/pull/297)
         
     | 
| 
       3 
14 
     | 
    
         | 
    
        data/docs/index.asciidoc
    CHANGED
    
    | 
         @@ -140,6 +140,35 @@ input { 
     | 
|
| 
       140 
140 
     | 
    
         
             
            }
         
     | 
| 
       141 
141 
     | 
    
         
             
            ---------------------------------------------------------------------------------------------------
         
     | 
| 
       142 
142 
     | 
    
         | 
| 
      
 143 
     | 
    
         
            +
            ==== Prepared Statements
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
            Using server side prepared statements can speed up execution times as the server optimises the query plan and execution.
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
            NOTE: Not all JDBC accessible technologies will support prepared statements.
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
            With the introduction of Prepared Statement support comes a different code execution path and some new settings. Most of the existing settings are still useful but there are several new settings for Prepared Statements to read up on.
         
     | 
| 
      
 150 
     | 
    
         
            +
            Use the boolean setting `use_prepared_statements` to enable this execution mode. Use the `prepared_statement_name` setting to specify a name for the Prepared Statement, this identifies the prepared statement locally and remotely and it should be unique in your config and on the database. Use the `prepared_statement_bind_values` array setting to specify the bind values, use the exact string `:sql_last_value` (multiple times if necessary) for the predefined parameter mentioned before. The `statement` (or `statement_path`) setting still holds the SQL statement but to use bind variables you must use the `?` character as a placeholder in the exact order found in the `prepared_statement_bind_values` array.
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
            NOTE: Building count queries around a prepared statement is not supported at this time and because jdbc paging uses count queries under the hood, jdbc paging is not supported with prepared statements at this time either. Therefore, `jdbc_paging_enabled`, `jdbc_page_size` settings are ignored when using prepared statements.
         
     | 
| 
      
 153 
     | 
    
         
            +
             
     | 
| 
      
 154 
     | 
    
         
            +
            Example:
         
     | 
| 
      
 155 
     | 
    
         
            +
            [source,ruby]
         
     | 
| 
      
 156 
     | 
    
         
            +
            ---------------------------------------------------------------------------------------------------
         
     | 
| 
      
 157 
     | 
    
         
            +
            input {
         
     | 
| 
      
 158 
     | 
    
         
            +
              jdbc {
         
     | 
| 
      
 159 
     | 
    
         
            +
                statement => "SELECT * FROM mgd.seq_sequence WHERE _sequence_key > ? AND _sequence_key < ? + ? ORDER BY _sequence_key ASC"
         
     | 
| 
      
 160 
     | 
    
         
            +
                prepared_statement_bind_values => [":sql_last_value", ":sql_last_value", 4]
         
     | 
| 
      
 161 
     | 
    
         
            +
                prepared_statement_name => "foobar"
         
     | 
| 
      
 162 
     | 
    
         
            +
                use_prepared_statements => true
         
     | 
| 
      
 163 
     | 
    
         
            +
                use_column_value => true
         
     | 
| 
      
 164 
     | 
    
         
            +
                tracking_column_type => "numeric"
         
     | 
| 
      
 165 
     | 
    
         
            +
                tracking_column => "_sequence_key"
         
     | 
| 
      
 166 
     | 
    
         
            +
                last_run_metadata_path => "/elastic/tmp/testing/confs/test-jdbc-int-sql_last_value.yml"
         
     | 
| 
      
 167 
     | 
    
         
            +
                # ... other configuration bits
         
     | 
| 
      
 168 
     | 
    
         
            +
              }
         
     | 
| 
      
 169 
     | 
    
         
            +
            }
         
     | 
| 
      
 170 
     | 
    
         
            +
            ---------------------------------------------------------------------------------------------------
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
       143 
172 
     | 
    
         | 
| 
       144 
173 
     | 
    
         
             
            [id="plugins-{type}s-{plugin}-options"]
         
     | 
| 
       145 
174 
     | 
    
         
             
            ==== Jdbc Input Configuration Options
         
     | 
| 
         @@ -149,7 +178,6 @@ This plugin supports the following configuration options plus the <<plugins-{typ 
     | 
|
| 
       149 
178 
     | 
    
         
             
            [cols="<,<,<",options="header",]
         
     | 
| 
       150 
179 
     | 
    
         
             
            |=======================================================================
         
     | 
| 
       151 
180 
     | 
    
         
             
            |Setting |Input type|Required
         
     | 
| 
       152 
     | 
    
         
            -
            | <<plugins-{type}s-{plugin}-plugin_timezone>> |<<string,string>>, one of `["local", "utc"]`|No
         
     | 
| 
       153 
181 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-clean_run>> |<<boolean,boolean>>|No
         
     | 
| 
       154 
182 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-columns_charset>> |<<hash,hash>>|No
         
     | 
| 
       155 
183 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-connection_retry_attempts>> |<<number,number>>|No
         
     | 
| 
         @@ -170,6 +198,9 @@ This plugin supports the following configuration options plus the <<plugins-{typ 
     | 
|
| 
       170 
198 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-last_run_metadata_path>> |<<string,string>>|No
         
     | 
| 
       171 
199 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-lowercase_column_names>> |<<boolean,boolean>>|No
         
     | 
| 
       172 
200 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-parameters>> |<<hash,hash>>|No
         
     | 
| 
      
 201 
     | 
    
         
            +
            | <<plugins-{type}s-{plugin}-plugin_timezone>> |<<string,string>>, one of `["local", "utc"]`|No
         
     | 
| 
      
 202 
     | 
    
         
            +
            | <<plugins-{type}s-{plugin}-prepared_statement_bind_values>> |<<array,array>>|No
         
     | 
| 
      
 203 
     | 
    
         
            +
            | <<plugins-{type}s-{plugin}-prepared_statement_name>> |<<string,string>>|No
         
     | 
| 
       173 
204 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-record_last_run>> |<<boolean,boolean>>|No
         
     | 
| 
       174 
205 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-schedule>> |<<string,string>>|No
         
     | 
| 
       175 
206 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-sequel_opts>> |<<hash,hash>>|No
         
     | 
| 
         @@ -179,6 +210,7 @@ This plugin supports the following configuration options plus the <<plugins-{typ 
     | 
|
| 
       179 
210 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-tracking_column>> |<<string,string>>|No
         
     | 
| 
       180 
211 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-tracking_column_type>> |<<string,string>>, one of `["numeric", "timestamp"]`|No
         
     | 
| 
       181 
212 
     | 
    
         
             
            | <<plugins-{type}s-{plugin}-use_column_value>> |<<boolean,boolean>>|No
         
     | 
| 
      
 213 
     | 
    
         
            +
            | <<plugins-{type}s-{plugin}-use_prepared_statements>> |<<boolean,boolean>>|No
         
     | 
| 
       182 
214 
     | 
    
         
             
            |=======================================================================
         
     | 
| 
       183 
215 
     | 
    
         | 
| 
       184 
216 
     | 
    
         
             
            Also see <<plugins-{type}s-{plugin}-common-options>> for a list of options supported by all
         
     | 
| 
         @@ -284,7 +316,7 @@ database timezone is UTC then you do not need to set either of these settings. 
     | 
|
| 
       284 
316 
     | 
    
         
             
              * Value type is <<string,string>>
         
     | 
| 
       285 
317 
     | 
    
         
             
              * There is no default value for this setting.
         
     | 
| 
       286 
318 
     | 
    
         | 
| 
       287 
     | 
    
         
            -
            JDBC driver class to load, for  
     | 
| 
      
 319 
     | 
    
         
            +
            JDBC driver class to load, for example, "org.apache.derby.jdbc.ClientDriver"
         
     | 
| 
       288 
320 
     | 
    
         
             
            NB per https://github.com/logstash-plugins/logstash-input-jdbc/issues/43 if you are using
         
     | 
| 
       289 
321 
     | 
    
         
             
            the Oracle JDBC driver (ojdbc6.jar) the correct `jdbc_driver_class` is `"Java::oracle.jdbc.driver.OracleDriver"`
         
     | 
| 
       290 
322 
     | 
    
         | 
| 
         @@ -409,6 +441,22 @@ Whether to force the lowercasing of identifier fields 
     | 
|
| 
       409 
441 
     | 
    
         | 
| 
       410 
442 
     | 
    
         
             
            Hash of query parameter, for example `{ "target_id" => "321" }`
         
     | 
| 
       411 
443 
     | 
    
         | 
| 
      
 444 
     | 
    
         
            +
            [id="plugins-{type}s-{plugin}-prepared_statement_bind_values"]
         
     | 
| 
      
 445 
     | 
    
         
            +
            ===== `prepared_statement_bind_values`
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
              * Value type is <<array,array>>
         
     | 
| 
      
 448 
     | 
    
         
            +
              * Default value is `[]`
         
     | 
| 
      
 449 
     | 
    
         
            +
             
     | 
| 
      
 450 
     | 
    
         
            +
            Array of bind values for the prepared statement. `:sql_last_value` is a reserved predefined string
         
     | 
| 
      
 451 
     | 
    
         
            +
             
     | 
| 
      
 452 
     | 
    
         
            +
            [id="plugins-{type}s-{plugin}-prepared_statement_name"]
         
     | 
| 
      
 453 
     | 
    
         
            +
            ===== `prepared_statement_name`
         
     | 
| 
      
 454 
     | 
    
         
            +
             
     | 
| 
      
 455 
     | 
    
         
            +
              * Value type is <<string,string>>
         
     | 
| 
      
 456 
     | 
    
         
            +
              * Default value is `""`
         
     | 
| 
      
 457 
     | 
    
         
            +
             
     | 
| 
      
 458 
     | 
    
         
            +
            Name given to the prepared statement. It must be unique in your config and in the database
         
     | 
| 
      
 459 
     | 
    
         
            +
             
     | 
| 
       412 
460 
     | 
    
         
             
            [id="plugins-{type}s-{plugin}-record_last_run"]
         
     | 
| 
       413 
461 
     | 
    
         
             
            ===== `record_last_run`
         
     | 
| 
       414 
462 
     | 
    
         | 
| 
         @@ -506,6 +554,13 @@ When set to `true`, uses the defined 
     | 
|
| 
       506 
554 
     | 
    
         
             
            <<plugins-{type}s-{plugin}-tracking_column>> value as the `:sql_last_value`. When set
         
     | 
| 
       507 
555 
     | 
    
         
             
            to `false`, `:sql_last_value` reflects the last time the query was executed.
         
     | 
| 
       508 
556 
     | 
    
         | 
| 
      
 557 
     | 
    
         
            +
            [id="plugins-{type}s-{plugin}-use_prepared_statements"]
         
     | 
| 
      
 558 
     | 
    
         
            +
            ===== `use_prepared_statements`
         
     | 
| 
      
 559 
     | 
    
         
            +
             
     | 
| 
      
 560 
     | 
    
         
            +
              * Value type is <<boolean,boolean>>
         
     | 
| 
      
 561 
     | 
    
         
            +
              * Default value is `false`
         
     | 
| 
      
 562 
     | 
    
         
            +
             
     | 
| 
      
 563 
     | 
    
         
            +
            When set to `true`, enables prepare statement usage
         
     | 
| 
       509 
564 
     | 
    
         | 
| 
       510 
565 
     | 
    
         
             
            [id="plugins-{type}s-{plugin}-common-options"]
         
     | 
| 
       511 
566 
     | 
    
         
             
            include::{include_path}/{type}.asciidoc[]
         
     | 
    
        data/lib/logstash/inputs/jdbc.rb
    CHANGED
    
    | 
         @@ -201,6 +201,12 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base 
     | 
|
| 
       201 
201 
     | 
    
         
             
              # this will only convert column0 that has ISO-8859-1 as an original encoding.
         
     | 
| 
       202 
202 
     | 
    
         
             
              config :columns_charset, :validate => :hash, :default => {}
         
     | 
| 
       203 
203 
     | 
    
         | 
| 
      
 204 
     | 
    
         
            +
              config :use_prepared_statements, :validate => :boolean, :default => false
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
              config :prepared_statement_name, :validate => :string, :default => ""
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
              config :prepared_statement_bind_values, :validate => :array, :default => []
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
       204 
210 
     | 
    
         
             
              attr_reader :database # for test mocking/stubbing
         
     | 
| 
       205 
211 
     | 
    
         | 
| 
       206 
212 
     | 
    
         
             
              public
         
     | 
| 
         @@ -217,17 +223,25 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base 
     | 
|
| 
       217 
223 
     | 
    
         
             
                  end
         
     | 
| 
       218 
224 
     | 
    
         
             
                end
         
     | 
| 
       219 
225 
     | 
    
         | 
| 
       220 
     | 
    
         
            -
                set_value_tracker(LogStash::PluginMixins::Jdbc::ValueTracking.build_last_value_tracker(self))
         
     | 
| 
       221 
     | 
    
         
            -
                set_statement_logger(LogStash::PluginMixins::Jdbc::CheckedCountLogger.new(@logger))
         
     | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
       223 
     | 
    
         
            -
                @enable_encoding = !@charset.nil? || !@columns_charset.empty?
         
     | 
| 
       224 
     | 
    
         
            -
             
     | 
| 
       225 
226 
     | 
    
         
             
                unless @statement.nil? ^ @statement_filepath.nil?
         
     | 
| 
       226 
227 
     | 
    
         
             
                  raise(LogStash::ConfigurationError, "Must set either :statement or :statement_filepath. Only one may be set at a time.")
         
     | 
| 
       227 
228 
     | 
    
         
             
                end
         
     | 
| 
       228 
229 
     | 
    
         | 
| 
       229 
230 
     | 
    
         
             
                @statement = ::File.read(@statement_filepath) if @statement_filepath
         
     | 
| 
       230 
231 
     | 
    
         | 
| 
      
 232 
     | 
    
         
            +
                # must validate prepared statement mode after trying to read in from @statement_filepath
         
     | 
| 
      
 233 
     | 
    
         
            +
                if @use_prepared_statements
         
     | 
| 
      
 234 
     | 
    
         
            +
                  validation_errors = validate_prepared_statement_mode
         
     | 
| 
      
 235 
     | 
    
         
            +
                  unless validation_errors.empty?
         
     | 
| 
      
 236 
     | 
    
         
            +
                    raise(LogStash::ConfigurationError, "Prepared Statement Mode validation errors: " + validation_errors.join(", "))
         
     | 
| 
      
 237 
     | 
    
         
            +
                  end
         
     | 
| 
      
 238 
     | 
    
         
            +
                end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                set_value_tracker(LogStash::PluginMixins::Jdbc::ValueTracking.build_last_value_tracker(self))
         
     | 
| 
      
 241 
     | 
    
         
            +
                set_statement_logger(LogStash::PluginMixins::Jdbc::CheckedCountLogger.new(@logger))
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
                @enable_encoding = !@charset.nil? || !@columns_charset.empty?
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
       231 
245 
     | 
    
         
             
                if (@jdbc_password_filepath and @jdbc_password)
         
     | 
| 
       232 
246 
     | 
    
         
             
                  raise(LogStash::ConfigurationError, "Only one of :jdbc_password, :jdbc_password_filepath may be set at a time.")
         
     | 
| 
       233 
247 
     | 
    
         
             
                end
         
     | 
| 
         @@ -248,7 +262,7 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base 
     | 
|
| 
       248 
262 
     | 
    
         | 
| 
       249 
263 
     | 
    
         
             
              # test injection points
         
     | 
| 
       250 
264 
     | 
    
         
             
              def set_statement_logger(instance)
         
     | 
| 
       251 
     | 
    
         
            -
                @ 
     | 
| 
      
 265 
     | 
    
         
            +
                @statement_handler = LogStash::PluginMixins::Jdbc::StatementHandler.build_statement_handler(self, instance)
         
     | 
| 
       252 
266 
     | 
    
         
             
              end
         
     | 
| 
       253 
267 
     | 
    
         | 
| 
       254 
268 
     | 
    
         
             
              def set_value_tracker(instance)
         
     | 
| 
         @@ -275,10 +289,24 @@ module LogStash module Inputs class Jdbc < LogStash::Inputs::Base 
     | 
|
| 
       275 
289 
     | 
    
         | 
| 
       276 
290 
     | 
    
         
             
              private
         
     | 
| 
       277 
291 
     | 
    
         | 
| 
      
 292 
     | 
    
         
            +
              def validate_prepared_statement_mode
         
     | 
| 
      
 293 
     | 
    
         
            +
                error_messages = []
         
     | 
| 
      
 294 
     | 
    
         
            +
                if @prepared_statement_name.empty?
         
     | 
| 
      
 295 
     | 
    
         
            +
                  error_messages << "must provide a name for the Prepared Statement, it must be unique for the db session"
         
     | 
| 
      
 296 
     | 
    
         
            +
                end
         
     | 
| 
      
 297 
     | 
    
         
            +
                if @statement.count("?") != @prepared_statement_bind_values.size
         
     | 
| 
      
 298 
     | 
    
         
            +
                  # mismatch in number of bind value elements to placeholder characters
         
     | 
| 
      
 299 
     | 
    
         
            +
                  error_messages << "there is a mismatch between the number of statement `?` placeholders and :prepared_statement_bind_values array setting elements"
         
     | 
| 
      
 300 
     | 
    
         
            +
                end
         
     | 
| 
      
 301 
     | 
    
         
            +
                if @jdbc_paging_enabled
         
     | 
| 
      
 302 
     | 
    
         
            +
                  # Pagination is not supported when using prepared statements
         
     | 
| 
      
 303 
     | 
    
         
            +
                  error_messages << "JDBC pagination cannot be used at this time"
         
     | 
| 
      
 304 
     | 
    
         
            +
                end
         
     | 
| 
      
 305 
     | 
    
         
            +
                error_messages
         
     | 
| 
      
 306 
     | 
    
         
            +
              end
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
       278 
308 
     | 
    
         
             
              def execute_query(queue)
         
     | 
| 
       279 
     | 
    
         
            -
                 
     | 
| 
       280 
     | 
    
         
            -
                @parameters['sql_last_value'] = @value_tracker.value
         
     | 
| 
       281 
     | 
    
         
            -
                execute_statement(@statement, @parameters) do |row|
         
     | 
| 
      
 309 
     | 
    
         
            +
                execute_statement do |row|
         
     | 
| 
       282 
310 
     | 
    
         
             
                  if enable_encoding?
         
     | 
| 
       283 
311 
     | 
    
         
             
                    ## do the necessary conversions to string elements
         
     | 
| 
       284 
312 
     | 
    
         
             
                    row = Hash[row.map { |k, v| [k.to_s, convert(k, v)] }]
         
     | 
| 
         @@ -9,9 +9,14 @@ module LogStash module PluginMixins module Jdbc 
     | 
|
| 
       9 
9 
     | 
    
         
             
                  @in_debug = @logger.debug?
         
     | 
| 
       10 
10 
     | 
    
         
             
                end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
                def  
     | 
| 
      
 12 
     | 
    
         
            +
                def disable_count
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @needs_check = false
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @count_is_supported = false
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def log_statement_parameters(statement, parameters, query)
         
     | 
| 
       13 
18 
     | 
    
         
             
                  return unless @in_debug
         
     | 
| 
       14 
     | 
    
         
            -
                  check_count_query(query) if @needs_check
         
     | 
| 
      
 19 
     | 
    
         
            +
                  check_count_query(query) if @needs_check && query
         
     | 
| 
       15 
20 
     | 
    
         
             
                  if @count_is_supported
         
     | 
| 
       16 
21 
     | 
    
         
             
                    @logger.debug("Executing JDBC query", :statement => statement, :parameters => parameters, :count => execute_count(query))
         
     | 
| 
       17 
22 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -35,4 +40,4 @@ module LogStash module PluginMixins module Jdbc 
     | 
|
| 
       35 
40 
     | 
    
         
             
                  query.count
         
     | 
| 
       36 
41 
     | 
    
         
             
                end
         
     | 
| 
       37 
42 
     | 
    
         
             
              end
         
     | 
| 
       38 
     | 
    
         
            -
            end end end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end end end
         
     | 
| 
         @@ -6,6 +6,7 @@ require "date" 
     | 
|
| 
       6 
6 
     | 
    
         
             
            require_relative "value_tracking"
         
     | 
| 
       7 
7 
     | 
    
         
             
            require_relative "checked_count_logger"
         
     | 
| 
       8 
8 
     | 
    
         
             
            require_relative "wrapped_driver"
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative "statement_handler"
         
     | 
| 
       9 
10 
     | 
    
         | 
| 
       10 
11 
     | 
    
         
             
            java_import java.util.concurrent.locks.ReentrantLock
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
         @@ -171,22 +172,24 @@ module LogStash  module PluginMixins module Jdbc 
     | 
|
| 
       171 
172 
     | 
    
         
             
                  require "sequel/adapters/jdbc"
         
     | 
| 
       172 
173 
     | 
    
         | 
| 
       173 
174 
     | 
    
         
             
                  Sequel.application_timezone = @plugin_timezone.to_sym
         
     | 
| 
       174 
     | 
    
         
            -
             
     | 
| 
       175 
     | 
    
         
            -
             
     | 
| 
       176 
     | 
    
         
            -
             
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
     | 
    
         
            -
             
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
       181 
     | 
    
         
            -
             
     | 
| 
       182 
     | 
    
         
            -
             
     | 
| 
       183 
     | 
    
         
            -
             
     | 
| 
       184 
     | 
    
         
            -
             
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
      
 175 
     | 
    
         
            +
                  if @drivers_loaded.false?
         
     | 
| 
      
 176 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 177 
     | 
    
         
            +
                      load_drivers
         
     | 
| 
      
 178 
     | 
    
         
            +
                      Sequel::JDBC.load_driver(@jdbc_driver_class)
         
     | 
| 
      
 179 
     | 
    
         
            +
                    rescue LogStash::Error => e
         
     | 
| 
      
 180 
     | 
    
         
            +
                      # raised in load_drivers, e.cause should be the caught Java exceptions
         
     | 
| 
      
 181 
     | 
    
         
            +
                      raise LogStash::PluginLoadingError, "#{e.message} and #{e.cause.message}"
         
     | 
| 
      
 182 
     | 
    
         
            +
                    rescue Sequel::AdapterNotFound => e
         
     | 
| 
      
 183 
     | 
    
         
            +
                      # fix this !!!
         
     | 
| 
      
 184 
     | 
    
         
            +
                      message = if @jdbc_driver_library.nil?
         
     | 
| 
      
 185 
     | 
    
         
            +
                        ":jdbc_driver_library is not set, are you sure you included
         
     | 
| 
      
 186 
     | 
    
         
            +
                                  the proper driver client libraries in your classpath?"
         
     | 
| 
      
 187 
     | 
    
         
            +
                      else
         
     | 
| 
      
 188 
     | 
    
         
            +
                        "Are you sure you've included the correct jdbc driver in :jdbc_driver_library?"
         
     | 
| 
      
 189 
     | 
    
         
            +
                      end
         
     | 
| 
      
 190 
     | 
    
         
            +
                      raise LogStash::PluginLoadingError, "#{e}. #{message}"
         
     | 
| 
       188 
191 
     | 
    
         
             
                    end
         
     | 
| 
       189 
     | 
    
         
            -
                     
     | 
| 
      
 192 
     | 
    
         
            +
                    @drivers_loaded.make_true
         
     | 
| 
       190 
193 
     | 
    
         
             
                  end
         
     | 
| 
       191 
194 
     | 
    
         
             
                  @database = jdbc_connect()
         
     | 
| 
       192 
195 
     | 
    
         
             
                  @database.extension(:pagination)
         
     | 
| 
         @@ -226,6 +229,7 @@ module LogStash  module PluginMixins module Jdbc 
     | 
|
| 
       226 
229 
     | 
    
         
             
                public
         
     | 
| 
       227 
230 
     | 
    
         
             
                def prepare_jdbc_connection
         
     | 
| 
       228 
231 
     | 
    
         
             
                  @connection_lock = ReentrantLock.new
         
     | 
| 
      
 232 
     | 
    
         
            +
                  @drivers_loaded = Concurrent::AtomicBoolean.new
         
     | 
| 
       229 
233 
     | 
    
         
             
                end
         
     | 
| 
       230 
234 
     | 
    
         | 
| 
       231 
235 
     | 
    
         
             
                public
         
     | 
| 
         @@ -243,18 +247,14 @@ module LogStash  module PluginMixins module Jdbc 
     | 
|
| 
       243 
247 
     | 
    
         
             
                end
         
     | 
| 
       244 
248 
     | 
    
         | 
| 
       245 
249 
     | 
    
         
             
                public
         
     | 
| 
       246 
     | 
    
         
            -
                def execute_statement 
     | 
| 
       247 
     | 
    
         
            -
                  # sql_last_value has been set in params by caller
         
     | 
| 
      
 250 
     | 
    
         
            +
                def execute_statement
         
     | 
| 
       248 
251 
     | 
    
         
             
                  success = false
         
     | 
| 
       249 
252 
     | 
    
         
             
                  @connection_lock.lock
         
     | 
| 
       250 
253 
     | 
    
         
             
                  open_jdbc_connection
         
     | 
| 
       251 
254 
     | 
    
         
             
                  begin
         
     | 
| 
       252 
     | 
    
         
            -
                    params = symbolized_params(parameters)
         
     | 
| 
       253 
     | 
    
         
            -
                    query = @database[statement, params]
         
     | 
| 
       254 
255 
     | 
    
         
             
                    sql_last_value = @use_column_value ? @value_tracker.value : Time.now.utc
         
     | 
| 
       255 
256 
     | 
    
         
             
                    @tracking_column_warning_sent = false
         
     | 
| 
       256 
     | 
    
         
            -
                    @ 
     | 
| 
       257 
     | 
    
         
            -
                    perform_query(query) do |row|
         
     | 
| 
      
 257 
     | 
    
         
            +
                    @statement_handler.perform_query(@database, @value_tracker.value) do |row|
         
     | 
| 
       258 
258 
     | 
    
         
             
                      sql_last_value = get_column_value(row) if @use_column_value
         
     | 
| 
       259 
259 
     | 
    
         
             
                      yield extract_values_from(row)
         
     | 
| 
       260 
260 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -270,24 +270,6 @@ module LogStash  module PluginMixins module Jdbc 
     | 
|
| 
       270 
270 
     | 
    
         
             
                  return success
         
     | 
| 
       271 
271 
     | 
    
         
             
                end
         
     | 
| 
       272 
272 
     | 
    
         | 
| 
       273 
     | 
    
         
            -
            # Performs the query, respecting our pagination settings, yielding once per row of data
         
     | 
| 
       274 
     | 
    
         
            -
            # @param query [Sequel::Dataset]
         
     | 
| 
       275 
     | 
    
         
            -
            # @yieldparam row [Hash{Symbol=>Object}]
         
     | 
| 
       276 
     | 
    
         
            -
                private
         
     | 
| 
       277 
     | 
    
         
            -
                def perform_query(query)
         
     | 
| 
       278 
     | 
    
         
            -
                  if @jdbc_paging_enabled
         
     | 
| 
       279 
     | 
    
         
            -
                    query.each_page(@jdbc_page_size) do |paged_dataset|
         
     | 
| 
       280 
     | 
    
         
            -
                      paged_dataset.each do |row|
         
     | 
| 
       281 
     | 
    
         
            -
                        yield row
         
     | 
| 
       282 
     | 
    
         
            -
                      end
         
     | 
| 
       283 
     | 
    
         
            -
                    end
         
     | 
| 
       284 
     | 
    
         
            -
                  else
         
     | 
| 
       285 
     | 
    
         
            -
                    query.each do |row|
         
     | 
| 
       286 
     | 
    
         
            -
                      yield row
         
     | 
| 
       287 
     | 
    
         
            -
                    end
         
     | 
| 
       288 
     | 
    
         
            -
                  end
         
     | 
| 
       289 
     | 
    
         
            -
                end
         
     | 
| 
       290 
     | 
    
         
            -
             
     | 
| 
       291 
273 
     | 
    
         
             
                public
         
     | 
| 
       292 
274 
     | 
    
         
             
                def get_column_value(row)
         
     | 
| 
       293 
275 
     | 
    
         
             
                  if !row.has_key?(@tracking_column.to_sym)
         
     | 
| 
         @@ -295,7 +277,7 @@ module LogStash  module PluginMixins module Jdbc 
     | 
|
| 
       295 
277 
     | 
    
         
             
                      @logger.warn("tracking_column not found in dataset.", :tracking_column => @tracking_column)
         
     | 
| 
       296 
278 
     | 
    
         
             
                      @tracking_column_warning_sent = true
         
     | 
| 
       297 
279 
     | 
    
         
             
                    end
         
     | 
| 
       298 
     | 
    
         
            -
                    # If we can't find the tracking column, return the current  
     | 
| 
      
 280 
     | 
    
         
            +
                    # If we can't find the tracking column, return the current value in the ivar
         
     | 
| 
       299 
281 
     | 
    
         
             
                    @value_tracker.value
         
     | 
| 
       300 
282 
     | 
    
         
             
                  else
         
     | 
| 
       301 
283 
     | 
    
         
             
                    # Otherwise send the updated tracking column
         
     | 
| 
         @@ -303,22 +285,8 @@ module LogStash  module PluginMixins module Jdbc 
     | 
|
| 
       303 
285 
     | 
    
         
             
                  end
         
     | 
| 
       304 
286 
     | 
    
         
             
                end
         
     | 
| 
       305 
287 
     | 
    
         | 
| 
       306 
     | 
    
         
            -
            # Symbolize parameters keys to use with Sequel
         
     | 
| 
       307 
     | 
    
         
            -
                private
         
     | 
| 
       308 
     | 
    
         
            -
                def symbolized_params(parameters)
         
     | 
| 
       309 
     | 
    
         
            -
                  parameters.inject({}) do |hash,(k,v)|
         
     | 
| 
       310 
     | 
    
         
            -
                    case v
         
     | 
| 
       311 
     | 
    
         
            -
                    when LogStash::Timestamp
         
     | 
| 
       312 
     | 
    
         
            -
                      hash[k.to_sym] = v.time
         
     | 
| 
       313 
     | 
    
         
            -
                    else
         
     | 
| 
       314 
     | 
    
         
            -
                      hash[k.to_sym] = v
         
     | 
| 
       315 
     | 
    
         
            -
                    end
         
     | 
| 
       316 
     | 
    
         
            -
                    hash
         
     | 
| 
       317 
     | 
    
         
            -
                  end
         
     | 
| 
       318 
     | 
    
         
            -
                end
         
     | 
| 
       319 
     | 
    
         
            -
             
     | 
| 
       320 
288 
     | 
    
         
             
                private
         
     | 
| 
       321 
     | 
    
         
            -
            #Stringify row keys and decorate values when necessary
         
     | 
| 
      
 289 
     | 
    
         
            +
                #Stringify row keys and decorate values when necessary
         
     | 
| 
       322 
290 
     | 
    
         
             
                def extract_values_from(row)
         
     | 
| 
       323 
291 
     | 
    
         
             
                  Hash[row.map { |k, v| [k.to_s, decorate_value(v)] }]
         
     | 
| 
       324 
292 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,129 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module LogStash module PluginMixins module Jdbc
         
     | 
| 
      
 4 
     | 
    
         
            +
              class StatementHandler
         
     | 
| 
      
 5 
     | 
    
         
            +
                def self.build_statement_handler(plugin, logger)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  klass = plugin.use_prepared_statements ? PreparedStatementHandler : NormalStatementHandler
         
     | 
| 
      
 7 
     | 
    
         
            +
                  klass.new(plugin, logger)
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                attr_reader :statement, :parameters, :statement_logger
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def initialize(plugin, statement_logger)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @statement = plugin.statement
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @statement_logger = statement_logger
         
     | 
| 
      
 15 
     | 
    
         
            +
                  post_init(plugin)
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def build_query(db, sql_last_value)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # override in subclass
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def post_init(plugin)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # override in subclass, if needed
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              class NormalStatementHandler < StatementHandler
         
     | 
| 
      
 28 
     | 
    
         
            +
                # Performs the query, respecting our pagination settings, yielding once per row of data
         
     | 
| 
      
 29 
     | 
    
         
            +
                # @param db [Sequel::Database]
         
     | 
| 
      
 30 
     | 
    
         
            +
                # @param sql_last_value [Integet|DateTime|Time]
         
     | 
| 
      
 31 
     | 
    
         
            +
                # @yieldparam row [Hash{Symbol=>Object}]
         
     | 
| 
      
 32 
     | 
    
         
            +
                def perform_query(db, sql_last_value)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  query = build_query(db, sql_last_value)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  if @jdbc_paging_enabled
         
     | 
| 
      
 35 
     | 
    
         
            +
                    query.each_page(@jdbc_page_size) do |paged_dataset|
         
     | 
| 
      
 36 
     | 
    
         
            +
                      paged_dataset.each do |row|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        yield row
         
     | 
| 
      
 38 
     | 
    
         
            +
                      end
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  else
         
     | 
| 
      
 41 
     | 
    
         
            +
                    query.each do |row|
         
     | 
| 
      
 42 
     | 
    
         
            +
                      yield row
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                private
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                def build_query(db, sql_last_value)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  parameters[:sql_last_value] = sql_last_value
         
     | 
| 
      
 51 
     | 
    
         
            +
                  query = db[statement, parameters]
         
     | 
| 
      
 52 
     | 
    
         
            +
                  statement_logger.log_statement_parameters(statement, parameters, query)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  query
         
     | 
| 
      
 54 
     | 
    
         
            +
                end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                def post_init(plugin)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @parameter_keys = ["sql_last_value"] + plugin.parameters.keys
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @parameters = plugin.parameters.inject({}) do |hash,(k,v)|
         
     | 
| 
      
 59 
     | 
    
         
            +
                    case v
         
     | 
| 
      
 60 
     | 
    
         
            +
                    when LogStash::Timestamp
         
     | 
| 
      
 61 
     | 
    
         
            +
                      hash[k.to_sym] = v.time
         
     | 
| 
      
 62 
     | 
    
         
            +
                    else
         
     | 
| 
      
 63 
     | 
    
         
            +
                      hash[k.to_sym] = v
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                    hash
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
              end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
              class PreparedStatementHandler < StatementHandler
         
     | 
| 
      
 71 
     | 
    
         
            +
                attr_reader :name, :bind_values_array, :statement_prepared, :prepared
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                # Performs the query, ignoring our pagination settings, yielding once per row of data
         
     | 
| 
      
 74 
     | 
    
         
            +
                # @param db [Sequel::Database]
         
     | 
| 
      
 75 
     | 
    
         
            +
                # @param sql_last_value [Integet|DateTime|Time]
         
     | 
| 
      
 76 
     | 
    
         
            +
                # @yieldparam row [Hash{Symbol=>Object}]
         
     | 
| 
      
 77 
     | 
    
         
            +
                def perform_query(db, sql_last_value)
         
     | 
| 
      
 78 
     | 
    
         
            +
                  query = build_query(db, sql_last_value)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  query.each do |row|
         
     | 
| 
      
 80 
     | 
    
         
            +
                    yield row
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                private
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                def build_query(db, sql_last_value)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  @parameters = create_bind_values_hash
         
     | 
| 
      
 88 
     | 
    
         
            +
                  if statement_prepared.false?
         
     | 
| 
      
 89 
     | 
    
         
            +
                    prepended = parameters.keys.map{|v| v.to_s.prepend("$").to_sym}
         
     | 
| 
      
 90 
     | 
    
         
            +
                    @prepared = db[statement, *prepended].prepare(:select, name)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    statement_prepared.make_true
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                  # under the scheduler the Sequel database instance is recreated each time
         
     | 
| 
      
 94 
     | 
    
         
            +
                  # so the previous prepared statements are lost, add back
         
     | 
| 
      
 95 
     | 
    
         
            +
                  if db.prepared_statement(name).nil?
         
     | 
| 
      
 96 
     | 
    
         
            +
                    db.set_prepared_statement(name, prepared)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  bind_value_sql_last_value(sql_last_value)
         
     | 
| 
      
 99 
     | 
    
         
            +
                  statement_logger.log_statement_parameters(statement, parameters, nil)
         
     | 
| 
      
 100 
     | 
    
         
            +
                  db.call(name, parameters)
         
     | 
| 
      
 101 
     | 
    
         
            +
                end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                def post_init(plugin)
         
     | 
| 
      
 104 
     | 
    
         
            +
                  # don't log statement count when using prepared statements for now...
         
     | 
| 
      
 105 
     | 
    
         
            +
                  # needs enhancement to allow user to supply a bindable count prepared statement in settings.
         
     | 
| 
      
 106 
     | 
    
         
            +
                  @statement_logger.disable_count
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                  @name = plugin.prepared_statement_name.to_sym
         
     | 
| 
      
 109 
     | 
    
         
            +
                  @bind_values_array = plugin.prepared_statement_bind_values
         
     | 
| 
      
 110 
     | 
    
         
            +
                  @parameters = plugin.parameters
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @statement_prepared = Concurrent::AtomicBoolean.new(false)
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                def create_bind_values_hash
         
     | 
| 
      
 115 
     | 
    
         
            +
                  hash = {}
         
     | 
| 
      
 116 
     | 
    
         
            +
                  bind_values_array.each_with_index {|v,i| hash[:"p#{i}"] = v}
         
     | 
| 
      
 117 
     | 
    
         
            +
                  hash
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                def bind_value_sql_last_value(sql_last_value)
         
     | 
| 
      
 121 
     | 
    
         
            +
                  parameters.keys.each do |key|
         
     | 
| 
      
 122 
     | 
    
         
            +
                    value = parameters[key]
         
     | 
| 
      
 123 
     | 
    
         
            +
                    if value == ":sql_last_value"
         
     | 
| 
      
 124 
     | 
    
         
            +
                      parameters[key] = sql_last_value
         
     | 
| 
      
 125 
     | 
    
         
            +
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
              end
         
     | 
| 
      
 129 
     | 
    
         
            +
            end end end
         
     | 
| 
         @@ -5,28 +5,26 @@ module LogStash module PluginMixins module Jdbc 
     | 
|
| 
       5 
5 
     | 
    
         
             
              class ValueTracking
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
                def self.build_last_value_tracker(plugin)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  handler = plugin.record_last_run ? FileHandler.new(plugin.last_run_metadata_path) : NullFileHandler.new(plugin.last_run_metadata_path)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  if plugin.record_last_run
         
     | 
| 
      
 10 
     | 
    
         
            +
                    handler = FileHandler.new(plugin.last_run_metadata_path)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  if plugin.clean_run
         
     | 
| 
      
 13 
     | 
    
         
            +
                    handler.clean
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
       8 
16 
     | 
    
         
             
                  if plugin.use_column_value && plugin.tracking_column_type == "numeric"
         
     | 
| 
       9 
17 
     | 
    
         
             
                    # use this irrespective of the jdbc_default_timezone setting
         
     | 
| 
       10 
     | 
    
         
            -
                     
     | 
| 
      
 18 
     | 
    
         
            +
                    NumericValueTracker.new(handler)
         
     | 
| 
       11 
19 
     | 
    
         
             
                  else
         
     | 
| 
       12 
20 
     | 
    
         
             
                    if plugin.jdbc_default_timezone.nil? || plugin.jdbc_default_timezone.empty?
         
     | 
| 
       13 
21 
     | 
    
         
             
                      # no TZ stuff for Sequel, use Time
         
     | 
| 
       14 
     | 
    
         
            -
                       
     | 
| 
      
 22 
     | 
    
         
            +
                      TimeValueTracker.new(handler)
         
     | 
| 
       15 
23 
     | 
    
         
             
                    else
         
     | 
| 
       16 
24 
     | 
    
         
             
                      # Sequel does timezone handling on DateTime only
         
     | 
| 
       17 
     | 
    
         
            -
                       
     | 
| 
      
 25 
     | 
    
         
            +
                      DateTimeValueTracker.new(handler)
         
     | 
| 
       18 
26 
     | 
    
         
             
                    end
         
     | 
| 
       19 
27 
     | 
    
         
             
                  end
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                  handler = NullFileHandler.new(plugin.last_run_metadata_path)
         
     | 
| 
       22 
     | 
    
         
            -
                  if plugin.record_last_run
         
     | 
| 
       23 
     | 
    
         
            -
                    handler = FileHandler.new(plugin.last_run_metadata_path)
         
     | 
| 
       24 
     | 
    
         
            -
                  end
         
     | 
| 
       25 
     | 
    
         
            -
                  if plugin.clean_run
         
     | 
| 
       26 
     | 
    
         
            -
                    handler.clean
         
     | 
| 
       27 
     | 
    
         
            -
                  end
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                  instance = klass.new(handler)
         
     | 
| 
       30 
28 
     | 
    
         
             
                end
         
     | 
| 
       31 
29 
     | 
    
         | 
| 
       32 
30 
     | 
    
         
             
                attr_reader :value
         
     | 
| 
         @@ -51,6 +49,7 @@ module LogStash module PluginMixins module Jdbc 
     | 
|
| 
       51 
49 
     | 
    
         
             
                private
         
     | 
| 
       52 
50 
     | 
    
         
             
                def common_set_initial(method_symbol, default)
         
     | 
| 
       53 
51 
     | 
    
         
             
                  persisted = @file_handler.read
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
       54 
53 
     | 
    
         
             
                  if persisted && persisted.respond_to?(method_symbol)
         
     | 
| 
       55 
54 
     | 
    
         
             
                    @value = persisted
         
     | 
| 
       56 
55 
     | 
    
         
             
                  else
         
     | 
    
        data/logstash-input-jdbc.gemspec
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Gem::Specification.new do |s|
         
     | 
| 
       2 
2 
     | 
    
         
             
              s.name = 'logstash-input-jdbc'
         
     | 
| 
       3 
     | 
    
         
            -
              s.version         = '4.3. 
     | 
| 
      
 3 
     | 
    
         
            +
              s.version         = '4.3.16'
         
     | 
| 
       4 
4 
     | 
    
         
             
              s.licenses = ['Apache License (2.0)']
         
     | 
| 
       5 
5 
     | 
    
         
             
              s.summary = "Creates events from JDBC data"
         
     | 
| 
       6 
6 
     | 
    
         
             
              s.description     = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
         
     | 
    
        data/spec/inputs/jdbc_spec.rb
    CHANGED
    
    | 
         @@ -1310,4 +1310,142 @@ describe LogStash::Inputs::Jdbc do 
     | 
|
| 
       1310 
1310 
     | 
    
         
             
                  end
         
     | 
| 
       1311 
1311 
     | 
    
         
             
                end
         
     | 
| 
       1312 
1312 
     | 
    
         
             
              end
         
     | 
| 
      
 1313 
     | 
    
         
            +
             
     | 
| 
      
 1314 
     | 
    
         
            +
              context "when using prepared statements" do
         
     | 
| 
      
 1315 
     | 
    
         
            +
                let(:last_run_value) { 250 }
         
     | 
| 
      
 1316 
     | 
    
         
            +
                let(:expected_queue_size) { 100 }
         
     | 
| 
      
 1317 
     | 
    
         
            +
                let(:num_rows) { 1000 }
         
     | 
| 
      
 1318 
     | 
    
         
            +
             
     | 
| 
      
 1319 
     | 
    
         
            +
                context "check validation" do
         
     | 
| 
      
 1320 
     | 
    
         
            +
                  context "with an empty name setting" do
         
     | 
| 
      
 1321 
     | 
    
         
            +
                    let(:settings) do
         
     | 
| 
      
 1322 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1323 
     | 
    
         
            +
                        "statement" => "SELECT * FROM test_table ORDER BY num FETCH NEXT ? ROWS ONLY",
         
     | 
| 
      
 1324 
     | 
    
         
            +
                        "prepared_statement_bind_values" => [100],
         
     | 
| 
      
 1325 
     | 
    
         
            +
                        "use_prepared_statements" => true,
         
     | 
| 
      
 1326 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1327 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1328 
     | 
    
         
            +
             
     | 
| 
      
 1329 
     | 
    
         
            +
                    it "should fail to register" do
         
     | 
| 
      
 1330 
     | 
    
         
            +
                      expect{ plugin.register }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 1331 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1332 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1333 
     | 
    
         
            +
             
     | 
| 
      
 1334 
     | 
    
         
            +
                  context "with an mismatched placeholder vs bind values" do
         
     | 
| 
      
 1335 
     | 
    
         
            +
                    let(:settings) do
         
     | 
| 
      
 1336 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1337 
     | 
    
         
            +
                        "statement" => "SELECT * FROM test_table ORDER BY num FETCH NEXT ? ROWS ONLY",
         
     | 
| 
      
 1338 
     | 
    
         
            +
                        "prepared_statement_bind_values" => [],
         
     | 
| 
      
 1339 
     | 
    
         
            +
                        "use_prepared_statements" => true,
         
     | 
| 
      
 1340 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1341 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1342 
     | 
    
         
            +
             
     | 
| 
      
 1343 
     | 
    
         
            +
                    it "should fail to register" do
         
     | 
| 
      
 1344 
     | 
    
         
            +
                      expect{ plugin.register }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 1345 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1346 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1347 
     | 
    
         
            +
             
     | 
| 
      
 1348 
     | 
    
         
            +
                  context "with jdbc paging enabled" do
         
     | 
| 
      
 1349 
     | 
    
         
            +
                    let(:settings) do
         
     | 
| 
      
 1350 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1351 
     | 
    
         
            +
                        "statement" => "SELECT * FROM test_table ORDER BY num FETCH NEXT 100 ROWS ONLY",
         
     | 
| 
      
 1352 
     | 
    
         
            +
                        "prepared_statement_bind_values" => [],
         
     | 
| 
      
 1353 
     | 
    
         
            +
                        "prepared_statement_name" => "pstmt_test_without",
         
     | 
| 
      
 1354 
     | 
    
         
            +
                        "use_prepared_statements" => true,
         
     | 
| 
      
 1355 
     | 
    
         
            +
                        "jdbc_paging_enabled" => true,
         
     | 
| 
      
 1356 
     | 
    
         
            +
                        "jdbc_page_size" => 20,
         
     | 
| 
      
 1357 
     | 
    
         
            +
                        "jdbc_fetch_size" => 10
         
     | 
| 
      
 1358 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1359 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1360 
     | 
    
         
            +
             
     | 
| 
      
 1361 
     | 
    
         
            +
                    it "should fail to register" do
         
     | 
| 
      
 1362 
     | 
    
         
            +
                      expect{ plugin.register }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 1363 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1364 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1365 
     | 
    
         
            +
             
     | 
| 
      
 1366 
     | 
    
         
            +
                end
         
     | 
| 
      
 1367 
     | 
    
         
            +
             
     | 
| 
      
 1368 
     | 
    
         
            +
                context "and no validation failures" do
         
     | 
| 
      
 1369 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 1370 
     | 
    
         
            +
                    ::File.write(settings["last_run_metadata_path"], YAML.dump(last_run_value))
         
     | 
| 
      
 1371 
     | 
    
         
            +
                    num_rows.times do |n|
         
     | 
| 
      
 1372 
     | 
    
         
            +
                      db[:test_table].insert(:num => n.succ, :string => SecureRandom.hex(8), :custom_time => Time.now.utc, :created_at => Time.now.utc)
         
     | 
| 
      
 1373 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1374 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1375 
     | 
    
         
            +
             
     | 
| 
      
 1376 
     | 
    
         
            +
                  after do
         
     | 
| 
      
 1377 
     | 
    
         
            +
                    plugin.stop
         
     | 
| 
      
 1378 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1379 
     | 
    
         
            +
             
     | 
| 
      
 1380 
     | 
    
         
            +
                  context "with jdbc paging enabled" do
         
     | 
| 
      
 1381 
     | 
    
         
            +
                    let(:settings) do
         
     | 
| 
      
 1382 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1383 
     | 
    
         
            +
                        "statement" => "SELECT * FROM test_table ORDER BY num FETCH NEXT 100 ROWS ONLY",
         
     | 
| 
      
 1384 
     | 
    
         
            +
                        "prepared_statement_bind_values" => [],
         
     | 
| 
      
 1385 
     | 
    
         
            +
                        "prepared_statement_name" => "pstmt_test_without",
         
     | 
| 
      
 1386 
     | 
    
         
            +
                        "use_prepared_statements" => true,
         
     | 
| 
      
 1387 
     | 
    
         
            +
                        "tracking_column_type" => "numeric",
         
     | 
| 
      
 1388 
     | 
    
         
            +
                        "tracking_column" => "num",
         
     | 
| 
      
 1389 
     | 
    
         
            +
                        "use_column_value" => true,
         
     | 
| 
      
 1390 
     | 
    
         
            +
                        "last_run_metadata_path" => Stud::Temporary.pathname,
         
     | 
| 
      
 1391 
     | 
    
         
            +
                        "jdbc_paging_enabled" => true,
         
     | 
| 
      
 1392 
     | 
    
         
            +
                        "jdbc_page_size" => 20,
         
     | 
| 
      
 1393 
     | 
    
         
            +
                        "jdbc_fetch_size" => 10
         
     | 
| 
      
 1394 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1395 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1396 
     | 
    
         
            +
             
     | 
| 
      
 1397 
     | 
    
         
            +
                    it "should fail to register" do
         
     | 
| 
      
 1398 
     | 
    
         
            +
                      expect{ plugin.register }.to raise_error(LogStash::ConfigurationError)
         
     | 
| 
      
 1399 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1400 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1401 
     | 
    
         
            +
             
     | 
| 
      
 1402 
     | 
    
         
            +
                  context "without placeholder and bind parameters" do
         
     | 
| 
      
 1403 
     | 
    
         
            +
                    let(:settings) do
         
     | 
| 
      
 1404 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1405 
     | 
    
         
            +
                        "statement" => "SELECT * FROM test_table ORDER BY num FETCH NEXT 100 ROWS ONLY",
         
     | 
| 
      
 1406 
     | 
    
         
            +
                        "prepared_statement_bind_values" => [],
         
     | 
| 
      
 1407 
     | 
    
         
            +
                        "prepared_statement_name" => "pstmt_test_without",
         
     | 
| 
      
 1408 
     | 
    
         
            +
                        "use_prepared_statements" => true,
         
     | 
| 
      
 1409 
     | 
    
         
            +
                        "tracking_column_type" => "numeric",
         
     | 
| 
      
 1410 
     | 
    
         
            +
                        "tracking_column" => "num",
         
     | 
| 
      
 1411 
     | 
    
         
            +
                        "use_column_value" => true,
         
     | 
| 
      
 1412 
     | 
    
         
            +
                        "last_run_metadata_path" => Stud::Temporary.pathname
         
     | 
| 
      
 1413 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1414 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1415 
     | 
    
         
            +
             
     | 
| 
      
 1416 
     | 
    
         
            +
                    it "should fetch some rows" do
         
     | 
| 
      
 1417 
     | 
    
         
            +
                      plugin.register
         
     | 
| 
      
 1418 
     | 
    
         
            +
                      plugin.run(queue)
         
     | 
| 
      
 1419 
     | 
    
         
            +
             
     | 
| 
      
 1420 
     | 
    
         
            +
                      expect(queue.size).to eq(expected_queue_size)
         
     | 
| 
      
 1421 
     | 
    
         
            +
                      expect(YAML.load(File.read(settings["last_run_metadata_path"]))).to eq(expected_queue_size)
         
     | 
| 
      
 1422 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1423 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1424 
     | 
    
         
            +
             
     | 
| 
      
 1425 
     | 
    
         
            +
             
     | 
| 
      
 1426 
     | 
    
         
            +
                  context "with bind parameters" do
         
     | 
| 
      
 1427 
     | 
    
         
            +
                    let(:settings) do
         
     | 
| 
      
 1428 
     | 
    
         
            +
                      {
         
     | 
| 
      
 1429 
     | 
    
         
            +
                        # Sadly, postgres does but derby doesn't - It is not allowed for both operands of '+' to be ? parameters.: PREPARE pstmt_test: SELECT * FROM test_table WHERE (num > ?) AND (num <= ? + ?) ORDER BY num
         
     | 
| 
      
 1430 
     | 
    
         
            +
                        "statement" => "SELECT * FROM test_table WHERE (num > ?) ORDER BY num FETCH NEXT ? ROWS ONLY",
         
     | 
| 
      
 1431 
     | 
    
         
            +
                        "prepared_statement_bind_values" => [":sql_last_value", expected_queue_size],
         
     | 
| 
      
 1432 
     | 
    
         
            +
                        "prepared_statement_name" => "pstmt_test_with",
         
     | 
| 
      
 1433 
     | 
    
         
            +
                        "use_prepared_statements" => true,
         
     | 
| 
      
 1434 
     | 
    
         
            +
                        "tracking_column_type" => "numeric",
         
     | 
| 
      
 1435 
     | 
    
         
            +
                        "tracking_column" => "num",
         
     | 
| 
      
 1436 
     | 
    
         
            +
                        "use_column_value" => true,
         
     | 
| 
      
 1437 
     | 
    
         
            +
                        "last_run_metadata_path" => Stud::Temporary.pathname
         
     | 
| 
      
 1438 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1439 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1440 
     | 
    
         
            +
             
     | 
| 
      
 1441 
     | 
    
         
            +
                    it "should fetch some rows" do
         
     | 
| 
      
 1442 
     | 
    
         
            +
                      plugin.register
         
     | 
| 
      
 1443 
     | 
    
         
            +
                      plugin.run(queue)
         
     | 
| 
      
 1444 
     | 
    
         
            +
             
     | 
| 
      
 1445 
     | 
    
         
            +
                      expect(queue.size).to eq(expected_queue_size)
         
     | 
| 
      
 1446 
     | 
    
         
            +
                      expect(YAML.load(File.read(settings["last_run_metadata_path"]))).to eq(last_run_value + expected_queue_size)
         
     | 
| 
      
 1447 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1448 
     | 
    
         
            +
                  end
         
     | 
| 
      
 1449 
     | 
    
         
            +
                end
         
     | 
| 
      
 1450 
     | 
    
         
            +
              end
         
     | 
| 
       1313 
1451 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: logstash-input-jdbc
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 4.3. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 4.3.16
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Elastic
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire:
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2019- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2019-09-09 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -174,6 +174,7 @@ files: 
     | 
|
| 
       174 
174 
     | 
    
         
             
            - lib/logstash/inputs/tzinfo_jruby_patch.rb
         
     | 
| 
       175 
175 
     | 
    
         
             
            - lib/logstash/plugin_mixins/jdbc/checked_count_logger.rb
         
     | 
| 
       176 
176 
     | 
    
         
             
            - lib/logstash/plugin_mixins/jdbc/jdbc.rb
         
     | 
| 
      
 177 
     | 
    
         
            +
            - lib/logstash/plugin_mixins/jdbc/statement_handler.rb
         
     | 
| 
       177 
178 
     | 
    
         
             
            - lib/logstash/plugin_mixins/jdbc/value_tracking.rb
         
     | 
| 
       178 
179 
     | 
    
         
             
            - lib/logstash/plugin_mixins/jdbc/wrapped_driver.rb
         
     | 
| 
       179 
180 
     | 
    
         
             
            - logstash-input-jdbc.gemspec
         
     |