ibm_db 5.2.0-x86-mingw32 → 5.4.0-x86-mingw32
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/CHANGES +9 -0
- data/LICENSE +55 -18
- data/README +1 -1
- data/debug.log +1 -0
- data/ext/Makefile +28 -24
- data/ext/ibm_db.c +66 -65
- data/ext/ibm_db.o +0 -0
- data/ext/ibm_db.so +0 -0
- data/ext/mkmf.log +26 -24
- data/ext/ruby_ibm_db_cli.c +1 -0
- data/ext/ruby_ibm_db_cli.o +0 -0
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1520 -1282
- data/lib/ibm_db.so +1 -0
- data/lib/mswin32/ibm_db.rb +3 -1
- data/lib/mswin32/rb3x/i386/ruby30/ibm_db.so +0 -0
- data/lib/mswin32/rb3x/i386/ruby31/ibm_db.so +0 -0
- data/test/active_record/connection_adapters/fake_adapter.rb +5 -2
- data/test/activejob/destroy_association_async_test.rb +305 -0
- data/test/activejob/destroy_async_job_not_present_test.rb +31 -0
- data/test/activejob/helper.rb +15 -0
- data/test/assets/schema_dump_5_1.yml +345 -0
- data/test/cases/adapter_prevent_writes_test.rb +334 -0
- data/test/cases/adapter_test.rb +432 -218
- data/test/cases/adapters/mysql2/active_schema_test.rb +85 -75
- data/test/cases/adapters/mysql2/auto_increment_test.rb +34 -0
- data/test/cases/adapters/mysql2/bind_parameter_test.rb +5 -3
- data/test/cases/adapters/mysql2/boolean_test.rb +6 -4
- data/test/cases/adapters/mysql2/case_sensitivity_test.rb +26 -24
- data/test/cases/adapters/mysql2/charset_collation_test.rb +20 -17
- data/test/cases/adapters/mysql2/connection_test.rb +48 -50
- data/test/cases/adapters/mysql2/count_deleted_rows_with_lock_test.rb +28 -0
- data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +23 -19
- data/test/cases/adapters/mysql2/enum_test.rb +32 -11
- data/test/cases/adapters/mysql2/explain_test.rb +13 -11
- data/test/cases/adapters/mysql2/json_test.rb +17 -188
- data/test/cases/adapters/mysql2/mysql2_adapter_prevent_writes_test.rb +208 -0
- data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +183 -28
- data/test/cases/adapters/mysql2/nested_deadlock_test.rb +75 -0
- data/test/cases/adapters/mysql2/optimizer_hints_test.rb +69 -0
- data/test/cases/adapters/mysql2/schema_migrations_test.rb +26 -21
- data/test/cases/adapters/mysql2/schema_test.rb +24 -22
- data/test/cases/adapters/mysql2/set_test.rb +32 -0
- data/test/cases/adapters/mysql2/sp_test.rb +10 -8
- data/test/cases/adapters/mysql2/sql_types_test.rb +8 -6
- data/test/cases/adapters/mysql2/table_options_test.rb +93 -10
- data/test/cases/adapters/mysql2/transaction_test.rb +151 -0
- data/test/cases/adapters/mysql2/unsigned_type_test.rb +11 -9
- data/test/cases/adapters/mysql2/virtual_column_test.rb +66 -0
- data/test/cases/adapters/postgresql/active_schema_test.rb +40 -25
- data/test/cases/adapters/postgresql/array_test.rb +118 -63
- data/test/cases/adapters/postgresql/bit_string_test.rb +12 -10
- data/test/cases/adapters/postgresql/bytea_test.rb +26 -25
- data/test/cases/adapters/postgresql/case_insensitive_test.rb +10 -9
- data/test/cases/adapters/postgresql/change_schema_test.rb +7 -5
- data/test/cases/adapters/postgresql/cidr_test.rb +2 -0
- data/test/cases/adapters/postgresql/citext_test.rb +58 -58
- data/test/cases/adapters/postgresql/collation_test.rb +17 -15
- data/test/cases/adapters/postgresql/composite_test.rb +25 -23
- data/test/cases/adapters/postgresql/connection_test.rb +73 -85
- data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +74 -0
- data/test/cases/adapters/postgresql/datatype_test.rb +19 -22
- data/test/cases/adapters/postgresql/date_test.rb +42 -0
- data/test/cases/adapters/postgresql/domain_test.rb +9 -7
- data/test/cases/adapters/postgresql/enum_test.rb +12 -10
- data/test/cases/adapters/postgresql/explain_test.rb +10 -8
- data/test/cases/adapters/postgresql/extension_migration_test.rb +13 -12
- data/test/cases/adapters/postgresql/foreign_table_test.rb +109 -0
- data/test/cases/adapters/postgresql/full_text_test.rb +8 -6
- data/test/cases/adapters/postgresql/geometric_test.rb +57 -63
- data/test/cases/adapters/postgresql/hstore_test.rb +288 -280
- data/test/cases/adapters/postgresql/infinity_test.rb +54 -15
- data/test/cases/adapters/postgresql/integer_test.rb +2 -0
- data/test/cases/adapters/postgresql/interval_test.rb +99 -0
- data/test/cases/adapters/postgresql/json_test.rb +16 -201
- data/test/cases/adapters/postgresql/ltree_test.rb +14 -16
- data/test/cases/adapters/postgresql/money_test.rb +47 -16
- data/test/cases/adapters/postgresql/network_test.rb +36 -28
- data/test/cases/adapters/postgresql/numbers_test.rb +7 -5
- data/test/cases/adapters/postgresql/optimizer_hints_test.rb +71 -0
- data/test/cases/adapters/postgresql/partitions_test.rb +22 -0
- data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +205 -0
- data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +178 -136
- data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +27 -0
- data/test/cases/adapters/postgresql/quoting_test.rb +12 -6
- data/test/cases/adapters/postgresql/range_test.rb +406 -292
- data/test/cases/adapters/postgresql/referential_integrity_test.rb +16 -15
- data/test/cases/adapters/postgresql/rename_table_test.rb +9 -8
- data/test/cases/adapters/postgresql/schema_authorization_test.rb +14 -23
- data/test/cases/adapters/postgresql/schema_test.rb +207 -91
- data/test/cases/adapters/postgresql/serial_test.rb +9 -7
- data/test/cases/adapters/postgresql/statement_pool_test.rb +26 -6
- data/test/cases/adapters/postgresql/timestamp_test.rb +17 -15
- data/test/cases/adapters/postgresql/transaction_nested_test.rb +114 -0
- data/test/cases/adapters/postgresql/transaction_test.rb +189 -0
- data/test/cases/adapters/postgresql/type_lookup_test.rb +12 -10
- data/test/cases/adapters/postgresql/utils_test.rb +11 -9
- data/test/cases/adapters/postgresql/uuid_test.rb +226 -109
- data/test/cases/adapters/postgresql/xml_test.rb +10 -14
- data/test/cases/adapters/sqlite3/collation_test.rb +26 -15
- data/test/cases/adapters/sqlite3/copy_table_test.rb +31 -28
- data/test/cases/adapters/sqlite3/explain_test.rb +13 -11
- data/test/cases/adapters/sqlite3/json_test.rb +29 -0
- data/test/cases/adapters/sqlite3/quoting_test.rb +35 -57
- data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +186 -0
- data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +318 -131
- data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +11 -11
- data/test/cases/adapters/sqlite3/statement_pool_test.rb +7 -6
- data/test/cases/adapters/sqlite3/transaction_test.rb +123 -0
- data/test/cases/aggregations_test.rb +14 -12
- data/test/cases/annotate_test.rb +46 -0
- data/test/cases/ar_schema_test.rb +153 -86
- data/test/cases/arel/attributes/attribute_test.rb +1145 -0
- data/test/cases/arel/attributes/math_test.rb +83 -0
- data/test/cases/arel/attributes_test.rb +27 -0
- data/test/cases/arel/collectors/bind_test.rb +40 -0
- data/test/cases/arel/collectors/composite_test.rb +47 -0
- data/test/cases/arel/collectors/sql_string_test.rb +41 -0
- data/test/cases/arel/collectors/substitute_bind_collector_test.rb +48 -0
- data/test/cases/arel/crud_test.rb +65 -0
- data/test/cases/arel/delete_manager_test.rb +53 -0
- data/test/cases/arel/factory_methods_test.rb +46 -0
- data/test/cases/arel/helper.rb +45 -0
- data/test/cases/arel/insert_manager_test.rb +241 -0
- data/test/cases/arel/nodes/and_test.rb +30 -0
- data/test/cases/arel/nodes/as_test.rb +36 -0
- data/test/cases/arel/nodes/ascending_test.rb +46 -0
- data/test/cases/arel/nodes/bin_test.rb +35 -0
- data/test/cases/arel/nodes/binary_test.rb +29 -0
- data/test/cases/arel/nodes/bind_param_test.rb +22 -0
- data/test/cases/arel/nodes/case_test.rb +96 -0
- data/test/cases/arel/nodes/casted_test.rb +18 -0
- data/test/cases/arel/nodes/comment_test.rb +22 -0
- data/test/cases/arel/nodes/count_test.rb +35 -0
- data/test/cases/arel/nodes/delete_statement_test.rb +36 -0
- data/test/cases/arel/nodes/descending_test.rb +46 -0
- data/test/cases/arel/nodes/distinct_test.rb +21 -0
- data/test/cases/arel/nodes/equality_test.rb +62 -0
- data/test/cases/arel/nodes/extract_test.rb +43 -0
- data/test/cases/arel/nodes/false_test.rb +21 -0
- data/test/cases/arel/nodes/grouping_test.rb +26 -0
- data/test/cases/arel/nodes/infix_operation_test.rb +42 -0
- data/test/cases/arel/nodes/insert_statement_test.rb +44 -0
- data/test/cases/arel/nodes/named_function_test.rb +48 -0
- data/test/cases/arel/nodes/node_test.rb +22 -0
- data/test/cases/arel/nodes/not_test.rb +31 -0
- data/test/cases/arel/nodes/or_test.rb +36 -0
- data/test/cases/arel/nodes/over_test.rb +69 -0
- data/test/cases/arel/nodes/select_core_test.rb +79 -0
- data/test/cases/arel/nodes/select_statement_test.rb +51 -0
- data/test/cases/arel/nodes/sql_literal_test.rb +75 -0
- data/test/cases/arel/nodes/sum_test.rb +35 -0
- data/test/cases/arel/nodes/table_alias_test.rb +29 -0
- data/test/cases/arel/nodes/true_test.rb +21 -0
- data/test/cases/arel/nodes/unary_operation_test.rb +41 -0
- data/test/cases/arel/nodes/update_statement_test.rb +60 -0
- data/test/cases/arel/nodes/window_test.rb +81 -0
- data/test/cases/arel/nodes_test.rb +34 -0
- data/test/cases/arel/select_manager_test.rb +1238 -0
- data/test/cases/arel/support/fake_record.rb +135 -0
- data/test/cases/arel/table_test.rb +216 -0
- data/test/cases/arel/update_manager_test.rb +126 -0
- data/test/cases/arel/visitors/dispatch_contamination_test.rb +78 -0
- data/test/cases/arel/visitors/dot_test.rb +90 -0
- data/test/cases/arel/visitors/mysql_test.rb +157 -0
- data/test/cases/arel/visitors/postgres_test.rb +366 -0
- data/test/cases/arel/visitors/sqlite_test.rb +75 -0
- data/test/cases/arel/visitors/to_sql_test.rb +750 -0
- data/test/cases/associations/belongs_to_associations_test.rb +510 -158
- data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +4 -2
- data/test/cases/associations/callbacks_test.rb +56 -38
- data/test/cases/associations/cascaded_eager_loading_test.rb +118 -61
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +138 -18
- data/test/cases/associations/eager_load_nested_include_test.rb +38 -37
- data/test/cases/associations/eager_singularization_test.rb +21 -21
- data/test/cases/associations/eager_test.rb +559 -415
- data/test/cases/associations/extension_test.rb +18 -12
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +234 -213
- data/test/cases/associations/has_many_associations_test.rb +1038 -465
- data/test/cases/associations/has_many_through_associations_test.rb +558 -249
- data/test/cases/associations/has_one_associations_test.rb +294 -129
- data/test/cases/associations/has_one_through_associations_test.rb +121 -75
- data/test/cases/associations/inner_join_association_test.rb +114 -38
- data/test/cases/associations/inverse_associations_test.rb +606 -398
- data/test/cases/associations/join_model_test.rb +158 -148
- data/test/cases/associations/left_outer_join_association_test.rb +59 -24
- data/test/cases/associations/nested_through_associations_test.rb +166 -109
- data/test/cases/associations/required_test.rb +35 -10
- data/test/cases/associations_test.rb +241 -110
- data/test/cases/attribute_methods/read_test.rb +11 -11
- data/test/cases/attribute_methods_test.rb +413 -298
- data/test/cases/attributes_test.rb +145 -27
- data/test/cases/autosave_association_test.rb +681 -436
- data/test/cases/base_prevent_writes_test.rb +229 -0
- data/test/cases/base_test.rb +599 -542
- data/test/cases/batches_test.rb +288 -82
- data/test/cases/binary_test.rb +26 -31
- data/test/cases/bind_parameter_test.rb +194 -21
- data/test/cases/boolean_test.rb +52 -0
- data/test/cases/cache_key_test.rb +110 -5
- data/test/cases/calculations_test.rb +740 -177
- data/test/cases/callbacks_test.rb +74 -207
- data/test/cases/clone_test.rb +15 -10
- data/test/cases/coders/json_test.rb +2 -0
- data/test/cases/coders/yaml_column_test.rb +16 -13
- data/test/cases/collection_cache_key_test.rb +177 -20
- data/test/cases/column_alias_test.rb +9 -7
- data/test/cases/column_definition_test.rb +10 -68
- data/test/cases/comment_test.rb +166 -107
- data/test/cases/connection_adapters/adapter_leasing_test.rb +14 -10
- data/test/cases/connection_adapters/connection_handler_test.rb +358 -51
- data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +400 -0
- data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +103 -0
- data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +499 -0
- data/test/cases/connection_adapters/connection_swapping_nested_test.rb +457 -0
- data/test/cases/connection_adapters/legacy_connection_handlers_multi_db_test.rb +486 -0
- data/test/cases/connection_adapters/legacy_connection_handlers_sharding_db_test.rb +586 -0
- data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +319 -138
- data/test/cases/connection_adapters/mysql_type_lookup_test.rb +62 -50
- data/test/cases/connection_adapters/schema_cache_test.rb +259 -26
- data/test/cases/connection_adapters/type_lookup_test.rb +96 -95
- data/test/cases/connection_management_test.rb +13 -11
- data/test/cases/connection_pool_test.rb +316 -83
- data/test/cases/core_test.rb +82 -58
- data/test/cases/counter_cache_test.rb +204 -50
- data/test/cases/custom_locking_test.rb +5 -3
- data/test/cases/database_configurations/hash_config_test.rb +74 -0
- data/test/cases/database_configurations/resolver_test.rb +150 -0
- data/test/cases/database_configurations_test.rb +145 -0
- data/test/cases/database_selector_test.rb +296 -0
- data/test/cases/database_statements_test.rb +18 -16
- data/test/cases/date_test.rb +8 -16
- data/test/cases/date_time_precision_test.rb +100 -78
- data/test/cases/date_time_test.rb +23 -8
- data/test/cases/defaults_test.rb +106 -71
- data/test/cases/delegated_type_test.rb +57 -0
- data/test/cases/dirty_test.rb +419 -223
- data/test/cases/disconnected_test.rb +6 -6
- data/test/cases/dup_test.rb +54 -27
- data/test/cases/enum_test.rb +461 -82
- data/test/cases/errors_test.rb +7 -7
- data/test/cases/explain_subscriber_test.rb +17 -15
- data/test/cases/explain_test.rb +11 -19
- data/test/cases/filter_attributes_test.rb +153 -0
- data/test/cases/finder_respond_to_test.rb +14 -14
- data/test/cases/finder_test.rb +669 -287
- data/test/cases/fixture_set/file_test.rb +34 -38
- data/test/cases/fixtures_test.rb +833 -176
- data/test/cases/forbidden_attributes_protection_test.rb +32 -67
- data/test/cases/habtm_destroy_order_test.rb +25 -25
- data/test/cases/helper.rb +78 -49
- data/test/cases/hot_compatibility_test.rb +33 -32
- data/test/cases/i18n_test.rb +18 -17
- data/test/cases/inheritance_test.rb +180 -115
- data/test/cases/insert_all_test.rb +489 -0
- data/test/cases/instrumentation_test.rb +101 -0
- data/test/cases/integration_test.rb +119 -31
- data/test/cases/invalid_connection_test.rb +18 -16
- data/test/cases/invertible_migration_test.rb +183 -43
- data/test/cases/json_attribute_test.rb +35 -0
- data/test/cases/json_serialization_test.rb +57 -58
- data/test/cases/json_shared_test_cases.rb +290 -0
- data/test/cases/locking_test.rb +413 -119
- data/test/cases/log_subscriber_test.rb +68 -26
- data/test/cases/marshal_serialization_test.rb +39 -0
- data/test/cases/migration/change_schema_test.rb +118 -72
- data/test/cases/migration/change_table_test.rb +138 -30
- data/test/cases/migration/check_constraint_test.rb +162 -0
- data/test/cases/migration/column_attributes_test.rb +45 -35
- data/test/cases/migration/column_positioning_test.rb +18 -6
- data/test/cases/migration/columns_test.rb +93 -77
- data/test/cases/migration/command_recorder_test.rb +121 -34
- data/test/cases/migration/compatibility_test.rb +578 -23
- data/test/cases/migration/create_join_table_test.rb +35 -25
- data/test/cases/migration/foreign_key_test.rb +503 -284
- data/test/cases/migration/helper.rb +4 -3
- data/test/cases/migration/index_test.rb +119 -70
- data/test/cases/migration/logger_test.rb +9 -6
- data/test/cases/migration/pending_migrations_test.rb +88 -34
- data/test/cases/migration/references_foreign_key_test.rb +164 -150
- data/test/cases/migration/references_index_test.rb +38 -19
- data/test/cases/migration/references_statements_test.rb +15 -14
- data/test/cases/migration/rename_table_test.rb +53 -30
- data/test/cases/migration_test.rb +637 -269
- data/test/cases/migrator_test.rb +191 -135
- data/test/cases/mixin_test.rb +7 -11
- data/test/cases/modules_test.rb +36 -34
- data/test/cases/multi_db_migrator_test.rb +223 -0
- data/test/cases/multiparameter_attributes_test.rb +60 -33
- data/test/cases/multiple_db_test.rb +16 -22
- data/test/cases/nested_attributes_test.rb +341 -320
- data/test/cases/nested_attributes_with_callbacks_test.rb +26 -24
- data/test/cases/null_relation_test.rb +84 -0
- data/test/cases/numeric_data_test.rb +93 -0
- data/test/cases/persistence_test.rb +361 -269
- data/test/cases/pooled_connections_test.rb +18 -26
- data/test/cases/prepared_statement_status_test.rb +48 -0
- data/test/cases/primary_keys_test.rb +210 -104
- data/test/cases/query_cache_test.rb +610 -141
- data/test/cases/quoting_test.rb +132 -31
- data/test/cases/readonly_test.rb +49 -48
- data/test/cases/reaper_test.rb +146 -32
- data/test/cases/reflection_test.rb +167 -156
- data/test/cases/relation/delegation_test.rb +49 -36
- data/test/cases/relation/delete_all_test.rb +117 -0
- data/test/cases/relation/merging_test.rb +319 -42
- data/test/cases/relation/mutation_test.rb +55 -93
- data/test/cases/relation/or_test.rb +129 -29
- data/test/cases/relation/predicate_builder_test.rb +21 -6
- data/test/cases/relation/record_fetch_warning_test.rb +5 -3
- data/test/cases/relation/select_test.rb +67 -0
- data/test/cases/relation/update_all_test.rb +317 -0
- data/test/cases/relation/where_chain_test.rb +68 -32
- data/test/cases/relation/where_clause_test.rb +136 -61
- data/test/cases/relation/where_test.rb +155 -48
- data/test/cases/relation_test.rb +266 -112
- data/test/cases/relations_test.rb +969 -744
- data/test/cases/reload_models_test.rb +13 -9
- data/test/cases/reserved_word_test.rb +141 -0
- data/test/cases/result_test.rb +68 -17
- data/test/cases/sanitize_test.rb +87 -71
- data/test/cases/schema_dumper_test.rb +221 -128
- data/test/cases/schema_loading_test.rb +3 -2
- data/test/cases/scoping/default_scoping_test.rb +185 -144
- data/test/cases/scoping/named_scoping_test.rb +177 -89
- data/test/cases/scoping/relation_scoping_test.rb +197 -75
- data/test/cases/secure_token_test.rb +18 -3
- data/test/cases/serialization_test.rb +30 -28
- data/test/cases/serialized_attribute_test.rb +133 -42
- data/test/cases/signed_id_test.rb +168 -0
- data/test/cases/statement_cache_test.rb +41 -24
- data/test/cases/statement_invalid_test.rb +42 -0
- data/test/cases/store_test.rb +180 -55
- data/test/cases/strict_loading_test.rb +473 -0
- data/test/cases/suppressor_test.rb +26 -12
- data/test/cases/tasks/database_tasks_test.rb +1258 -194
- data/test/cases/tasks/mysql_rake_test.rb +370 -298
- data/test/cases/tasks/postgresql_rake_test.rb +481 -251
- data/test/cases/tasks/sqlite_rake_test.rb +225 -178
- data/test/cases/test_case.rb +51 -40
- data/test/cases/test_databases_test.rb +79 -0
- data/test/cases/test_fixtures_test.rb +79 -19
- data/test/cases/time_precision_test.rb +98 -76
- data/test/cases/timestamp_test.rb +102 -99
- data/test/cases/touch_later_test.rb +12 -10
- data/test/cases/transaction_callbacks_test.rb +344 -90
- data/test/cases/transaction_isolation_test.rb +12 -12
- data/test/cases/transactions_test.rb +612 -162
- data/test/cases/type/adapter_specific_registry_test.rb +14 -2
- data/test/cases/type/date_time_test.rb +4 -2
- data/test/cases/type/integer_test.rb +4 -2
- data/test/cases/type/string_test.rb +10 -8
- data/test/cases/type/time_test.rb +28 -0
- data/test/cases/type/type_map_test.rb +29 -28
- data/test/cases/type/unsigned_integer_test.rb +19 -0
- data/test/cases/type_test.rb +2 -0
- data/test/cases/types_test.rb +3 -1
- data/test/cases/unconnected_test.rb +14 -1
- data/test/cases/unsafe_raw_sql_test.rb +274 -0
- data/test/cases/validations/absence_validation_test.rb +19 -17
- data/test/cases/validations/association_validation_test.rb +30 -28
- data/test/cases/validations/i18n_generate_message_validation_test.rb +34 -16
- data/test/cases/validations/i18n_validation_test.rb +22 -21
- data/test/cases/validations/length_validation_test.rb +34 -33
- data/test/cases/validations/numericality_validation_test.rb +181 -0
- data/test/cases/validations/presence_validation_test.rb +21 -19
- data/test/cases/validations/uniqueness_validation_test.rb +156 -86
- data/test/cases/validations_repair_helper.rb +2 -0
- data/test/cases/validations_test.rb +61 -26
- data/test/cases/view_test.rb +122 -116
- data/test/cases/yaml_serialization_test.rb +79 -34
- data/test/config.example.yml +19 -19
- data/test/config.rb +3 -1
- data/test/config.yml +16 -6
- data/test/fixtures/all/namespaced/accounts.yml +2 -0
- data/test/fixtures/author_addresses.yml +1 -8
- data/test/fixtures/authors.yml +1 -7
- data/test/fixtures/binaries.yml +4 -0
- data/test/fixtures/books.yml +9 -2
- data/test/fixtures/categories_posts.yml +3 -0
- data/test/fixtures/citations.yml +5 -0
- data/test/fixtures/comments.yml +7 -0
- data/test/fixtures/companies.yml +5 -0
- data/test/fixtures/computers.yml +2 -0
- data/test/fixtures/customers.yml +10 -1
- data/test/fixtures/developers.yml +1 -1
- data/test/fixtures/essays.yml +10 -0
- data/test/fixtures/faces.yml +3 -3
- data/test/fixtures/humans.yml +5 -0
- data/test/fixtures/interests.yml +7 -7
- data/test/fixtures/memberships.yml +7 -0
- data/test/fixtures/minimalistics.yml +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +2 -2
- data/test/fixtures/naked/yml/courses_with_invalid_key.yml +3 -0
- data/test/fixtures/naked/yml/parrots.yml +1 -0
- data/test/fixtures/other_books.yml +26 -0
- data/test/fixtures/other_posts.yml +1 -0
- data/test/fixtures/parrots.yml +7 -1
- data/test/fixtures/pirates.yml +3 -0
- data/test/fixtures/posts.yml +11 -3
- data/test/fixtures/readers.yml +6 -0
- data/test/fixtures/reserved_words/values.yml +2 -2
- data/test/fixtures/sponsors.yml +3 -0
- data/test/fixtures/strict_zines.yml +2 -0
- data/test/fixtures/subscribers.yml +1 -1
- data/test/fixtures/tasks.yml +1 -1
- data/test/fixtures/warehouse-things.yml +3 -0
- data/test/migrations/10_urban/9_add_expressions.rb +2 -0
- data/test/migrations/decimal/1_give_me_big_numbers.rb +6 -4
- data/test/migrations/magic/1_currencies_have_symbols.rb +3 -2
- data/test/migrations/missing/1000_people_have_middle_names.rb +2 -0
- data/test/migrations/missing/1_people_have_last_names.rb +2 -0
- data/test/migrations/missing/3_we_need_reminders.rb +2 -0
- data/test/migrations/missing/4_innocent_jointable.rb +3 -1
- data/test/migrations/rename/1_we_need_things.rb +2 -0
- data/test/migrations/rename/2_rename_things.rb +2 -0
- data/test/migrations/to_copy/1_people_have_hobbies.rb +3 -1
- data/test/migrations/to_copy/2_people_have_descriptions.rb +3 -1
- data/test/migrations/to_copy2/1_create_articles.rb +2 -0
- data/test/migrations/to_copy2/2_create_comments.rb +3 -1
- data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +3 -1
- data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +3 -1
- data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +3 -1
- data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +2 -0
- data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +2 -0
- data/test/migrations/valid/1_valid_people_have_last_names.rb +2 -0
- data/test/migrations/valid/2_we_need_reminders.rb +2 -0
- data/test/migrations/valid/3_innocent_jointable.rb +3 -1
- data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +2 -0
- data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +2 -0
- data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +3 -1
- data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +2 -0
- data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +2 -0
- data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +3 -1
- data/test/migrations/version_check/20131219224947_migration_version_check.rb +2 -0
- data/test/models/account.rb +46 -0
- data/test/models/admin/account.rb +3 -1
- data/test/models/admin/randomly_named_c1.rb +2 -0
- data/test/models/admin/user.rb +16 -8
- data/test/models/admin.rb +4 -2
- data/test/models/aircraft.rb +3 -1
- data/test/models/arunit2_model.rb +2 -0
- data/test/models/author.rb +153 -102
- data/test/models/auto_id.rb +2 -0
- data/test/models/autoloadable/extra_firm.rb +2 -0
- data/test/models/binary.rb +3 -1
- data/test/models/binary_field.rb +6 -0
- data/test/models/bird.rb +13 -1
- data/test/models/book.rb +14 -4
- data/test/models/book_destroy_async.rb +24 -0
- data/test/models/boolean.rb +5 -0
- data/test/models/bulb.rb +13 -4
- data/test/models/cake_designer.rb +2 -0
- data/test/models/car.rb +17 -10
- data/test/models/carrier.rb +2 -0
- data/test/models/cart.rb +5 -0
- data/test/models/cat.rb +2 -0
- data/test/models/categorization.rb +8 -6
- data/test/models/category.rb +28 -16
- data/test/models/chef.rb +2 -0
- data/test/models/citation.rb +5 -1
- data/test/models/club.rb +13 -10
- data/test/models/college.rb +4 -2
- data/test/models/column.rb +2 -0
- data/test/models/column_name.rb +2 -0
- data/test/models/comment.rb +32 -10
- data/test/models/company.rb +102 -106
- data/test/models/company_in_module.rb +27 -26
- data/test/models/computer.rb +3 -1
- data/test/models/contact.rb +15 -13
- data/test/models/content.rb +5 -3
- data/test/models/contract.rb +21 -3
- data/test/models/country.rb +2 -4
- data/test/models/course.rb +3 -1
- data/test/models/customer.rb +10 -8
- data/test/models/customer_carrier.rb +2 -0
- data/test/models/dashboard.rb +2 -0
- data/test/models/default.rb +2 -0
- data/test/models/department.rb +2 -0
- data/test/models/destroy_async_parent.rb +15 -0
- data/test/models/destroy_async_parent_soft_delete.rb +20 -0
- data/test/models/developer.rb +152 -85
- data/test/models/dl_keyed_belongs_to.rb +13 -0
- data/test/models/dl_keyed_belongs_to_soft_delete.rb +19 -0
- data/test/models/dl_keyed_has_many.rb +5 -0
- data/test/models/dl_keyed_has_many_through.rb +5 -0
- data/test/models/dl_keyed_has_one.rb +5 -0
- data/test/models/dl_keyed_join.rb +10 -0
- data/test/models/dog.rb +2 -0
- data/test/models/dog_lover.rb +2 -0
- data/test/models/doubloon.rb +3 -1
- data/test/models/drink_designer.rb +17 -0
- data/test/models/edge.rb +4 -2
- data/test/models/electron.rb +2 -0
- data/test/models/engine.rb +3 -2
- data/test/models/entrant.rb +2 -0
- data/test/models/entry.rb +5 -0
- data/test/models/essay.rb +6 -3
- data/test/models/essay_destroy_async.rb +12 -0
- data/test/models/event.rb +3 -1
- data/test/models/eye.rb +5 -3
- data/test/models/face.rb +14 -6
- data/test/models/family.rb +6 -0
- data/test/models/family_tree.rb +6 -0
- data/test/models/friendship.rb +5 -3
- data/test/models/frog.rb +8 -0
- data/test/models/guid.rb +3 -1
- data/test/models/guitar.rb +2 -0
- data/test/models/hotel.rb +5 -3
- data/test/models/human.rb +39 -0
- data/test/models/image.rb +3 -1
- data/test/models/interest.rb +14 -3
- data/test/models/invoice.rb +4 -2
- data/test/models/item.rb +3 -1
- data/test/models/job.rb +5 -3
- data/test/models/joke.rb +4 -2
- data/test/models/keyboard.rb +3 -1
- data/test/models/legacy_thing.rb +2 -0
- data/test/models/lesson.rb +2 -0
- data/test/models/line_item.rb +3 -1
- data/test/models/liquid.rb +2 -0
- data/test/models/matey.rb +3 -1
- data/test/models/measurement.rb +4 -0
- data/test/models/member.rb +23 -20
- data/test/models/member_detail.rb +3 -0
- data/test/models/member_type.rb +2 -0
- data/test/models/membership.rb +4 -1
- data/test/models/mentor.rb +3 -1
- data/test/models/message.rb +5 -0
- data/test/models/minimalistic.rb +2 -0
- data/test/models/minivan.rb +3 -2
- data/test/models/mixed_case_monkey.rb +3 -1
- data/test/models/molecule.rb +2 -0
- data/test/models/mouse.rb +6 -0
- data/test/models/movie.rb +2 -0
- data/test/models/node.rb +4 -2
- data/test/models/non_primary_key.rb +2 -0
- data/test/models/notification.rb +2 -0
- data/test/models/numeric_data.rb +12 -0
- data/test/models/order.rb +4 -2
- data/test/models/organization.rb +9 -7
- data/test/models/other_dog.rb +3 -1
- data/test/models/owner.rb +6 -4
- data/test/models/parrot.rb +12 -4
- data/test/models/person.rb +59 -54
- data/test/models/personal_legacy_thing.rb +3 -1
- data/test/models/pet.rb +4 -2
- data/test/models/pet_treasure.rb +2 -0
- data/test/models/pirate.rb +67 -43
- data/test/models/possession.rb +3 -1
- data/test/models/post.rb +184 -86
- data/test/models/price_estimate.rb +11 -1
- data/test/models/professor.rb +3 -1
- data/test/models/project.rb +14 -12
- data/test/models/publisher/article.rb +2 -0
- data/test/models/publisher/magazine.rb +2 -0
- data/test/models/publisher.rb +2 -0
- data/test/models/randomly_named_c1.rb +2 -0
- data/test/models/rating.rb +5 -1
- data/test/models/reader.rb +7 -5
- data/test/models/recipe.rb +2 -0
- data/test/models/record.rb +2 -0
- data/test/models/reference.rb +6 -3
- data/test/models/reply.rb +39 -21
- data/test/models/room.rb +6 -0
- data/test/models/section.rb +6 -0
- data/test/models/seminar.rb +6 -0
- data/test/models/session.rb +6 -0
- data/test/models/ship.rb +12 -9
- data/test/models/ship_part.rb +5 -3
- data/test/models/shop.rb +4 -2
- data/test/models/shop_account.rb +2 -0
- data/test/models/speedometer.rb +2 -0
- data/test/models/sponsor.rb +8 -5
- data/test/models/squeak.rb +6 -0
- data/test/models/strict_zine.rb +7 -0
- data/test/models/string_key_object.rb +2 -0
- data/test/models/student.rb +2 -0
- data/test/models/subscriber.rb +4 -2
- data/test/models/subscription.rb +5 -1
- data/test/models/tag.rb +6 -3
- data/test/models/tagging.rb +13 -6
- data/test/models/task.rb +2 -0
- data/test/models/topic.rb +54 -19
- data/test/models/toy.rb +4 -0
- data/test/models/traffic_light.rb +2 -0
- data/test/models/treasure.rb +5 -3
- data/test/models/treaty.rb +2 -4
- data/test/models/tree.rb +2 -0
- data/test/models/tuning_peg.rb +2 -0
- data/test/models/tyre.rb +2 -0
- data/test/models/user.rb +12 -4
- data/test/models/uuid_child.rb +2 -0
- data/test/models/uuid_item.rb +2 -0
- data/test/models/uuid_parent.rb +2 -0
- data/test/models/vegetables.rb +12 -3
- data/test/models/vertex.rb +6 -4
- data/test/models/warehouse_thing.rb +2 -0
- data/test/models/wheel.rb +3 -1
- data/test/models/without_table.rb +3 -1
- data/test/models/zine.rb +3 -1
- data/test/schema/mysql2_specific_schema.rb +49 -35
- data/test/schema/oracle_specific_schema.rb +13 -15
- data/test/schema/postgresql_specific_schema.rb +51 -40
- data/test/schema/schema.rb +334 -154
- data/test/schema/sqlite_specific_schema.rb +9 -16
- data/test/support/config.rb +26 -26
- data/test/support/connection.rb +14 -8
- data/test/support/connection_helper.rb +3 -1
- data/test/support/ddl_helper.rb +2 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_0_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/legacy_6_0_record_mysql.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/legacy_relation.dump +0 -0
- data/test/support/schema_dumping_helper.rb +2 -0
- data/test/support/stubs/strong_parameters.rb +40 -0
- data/test/support/yaml_compatibility_fixtures/rails_v1_mysql.yml +206 -0
- data/test/support/yaml_compatibility_fixtures/rails_v2.yml +55 -0
- metadata +192 -14
@@ -1,7 +1,7 @@
|
|
1
1
|
# +----------------------------------------------------------------------+
|
2
2
|
# | Licensed Materials - Property of IBM |
|
3
3
|
# | |
|
4
|
-
# | (C) Copyright IBM Corporation 2006-
|
4
|
+
# | (C) Copyright IBM Corporation 2006 - 2022 |
|
5
5
|
# +----------------------------------------------------------------------+
|
6
6
|
# | Authors: Antonio Cangiano <cangiano@ca.ibm.com> |
|
7
7
|
# | : Mario Ds Briggs <mario.briggs@in.ibm.com> |
|
@@ -15,157 +15,196 @@ require 'arel/visitors/visitor'
|
|
15
15
|
require 'active_support/core_ext/string/strip'
|
16
16
|
require 'active_record/type'
|
17
17
|
require 'active_record/connection_adapters/sql_type_metadata'
|
18
|
-
|
19
|
-
|
18
|
+
require "active_record/connection_adapters/statement_pool"
|
19
|
+
require 'active_record/connection_adapters'
|
20
20
|
|
21
21
|
module CallChain
|
22
22
|
def self.caller_method(depth=1)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
private
|
23
|
+
parse_caller(caller(depth+1).first).last
|
24
|
+
end
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
26
|
+
private
|
27
|
+
# Copied from ActionMailer
|
28
|
+
def self.parse_caller(at)
|
29
|
+
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
|
30
|
+
file = Regexp.last_match[1]
|
31
|
+
line = Regexp.last_match[2].to_i
|
32
|
+
method = Regexp.last_match[3]
|
33
|
+
[file, line, method]
|
34
|
+
end
|
35
|
+
end
|
37
36
|
end
|
38
37
|
|
39
|
-
|
40
38
|
module ActiveRecord
|
41
|
-
|
42
|
-
|
43
|
-
class SchemaMigration < ActiveRecord::Base
|
44
|
-
class << self
|
39
|
+
class SchemaMigration < ActiveRecord::Base
|
40
|
+
class << self
|
45
41
|
def create_table
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
connection.create_table(table_name,id:false) do |t|
|
52
|
-
t.string :version, version_options
|
53
|
-
end
|
42
|
+
unless connection.table_exists?(table_name)
|
43
|
+
connection.create_table(table_name, id: false) do |t|
|
44
|
+
t.string :version, **connection.internal_string_options_for_primary_key
|
45
|
+
end
|
46
|
+
end
|
54
47
|
end
|
55
|
-
end
|
56
|
-
end
|
57
48
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
class Relation
|
49
|
+
end
|
62
50
|
|
63
|
-
|
64
|
-
|
51
|
+
module ConnectionAdapters
|
52
|
+
class SchemaDumper
|
53
|
+
private
|
54
|
+
def header(stream)
|
55
|
+
stream.puts <<~HEADER
|
56
|
+
ActiveRecord::Schema[#{ActiveRecord::Migration.current_version}].define(#{define_params}) do
|
57
|
+
HEADER
|
58
|
+
end
|
65
59
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
}]
|
60
|
+
def default_primary_key?(column)
|
61
|
+
schema_type(column) == :integer
|
62
|
+
end
|
70
63
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
64
|
+
def explicit_primary_key_default?(column)
|
65
|
+
column.bigint? and column.name == 'id'
|
66
|
+
end
|
67
|
+
end
|
76
68
|
|
77
|
-
|
78
|
-
|
69
|
+
class SchemaCreation
|
70
|
+
private
|
71
|
+
def visit_TableDefinition(o)
|
72
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
73
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
74
|
+
create_sql << "#{quote_table_name(o.name)} "
|
79
75
|
|
80
|
-
|
76
|
+
statements = o.columns.map { |c| accept c }
|
77
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
79
|
+
if supports_indexes_in_create?
|
80
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
81
|
+
end
|
86
82
|
|
87
|
-
|
88
|
-
|
89
|
-
|
83
|
+
if supports_foreign_keys?
|
84
|
+
statements.concat(o.foreign_keys.map { |fk| accept fk })
|
85
|
+
end
|
90
86
|
|
91
|
-
|
87
|
+
if supports_check_constraints?
|
88
|
+
statements.concat(o.check_constraints.map { |chk| accept chk })
|
89
|
+
end
|
92
90
|
|
91
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
92
|
+
add_table_options!(create_sql, o)
|
93
|
+
create_sql << " AS (#{to_sql(o.as)}) WITH DATA" if o.as
|
94
|
+
create_sql
|
95
|
+
end
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
97
|
+
def add_column_options!(sql, options)
|
98
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
99
|
+
if options[:auto_increment] == true
|
100
|
+
sql << " GENERATED BY DEFAULT AS IDENTITY (START WITH 1000)"
|
101
|
+
end
|
102
|
+
if options[:primary_key] == true
|
103
|
+
sql << " PRIMARY KEY"
|
104
|
+
end
|
105
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
106
|
+
if options[:null] == false
|
107
|
+
sql << " NOT NULL"
|
108
|
+
end
|
109
|
+
sql
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Relation
|
115
|
+
|
116
|
+
def insert(values)
|
117
|
+
primary_key_value = nil
|
118
|
+
|
119
|
+
if primary_key && Hash === values
|
120
|
+
primary_key_value = values[values.keys.find { |k|
|
121
|
+
k.name == primary_key
|
122
|
+
}]
|
123
|
+
|
124
|
+
if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
|
125
|
+
primary_key_value = connection.next_sequence_value(klass.sequence_name)
|
126
|
+
values[klass.arel_table[klass.primary_key]] = primary_key_value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
im = arel.create_insert
|
131
|
+
im.into @table
|
132
|
+
|
133
|
+
conn = @klass.connection
|
134
|
+
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
|
135
|
+
binds = substitutes.map do |arel_attr, value|
|
136
|
+
[@klass.columns_hash[arel_attr.name], value]
|
137
|
+
end
|
110
138
|
|
111
|
-
|
139
|
+
substitutes, binds = substitute_values values
|
140
|
+
if values.empty? # empty insert
|
141
|
+
im.values = Arel.sql(connection.empty_insert_statement_value(klass.primary_key, klass.table_name))
|
142
|
+
else
|
143
|
+
im.insert substitutes
|
144
|
+
end
|
145
|
+
|
146
|
+
conn.insert(im, 'SQL', primary_key, primary_key_value, nil, binds)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class Base
|
112
151
|
# Method required to handle LOBs and XML fields.
|
113
152
|
# An after save callback checks if a marker has been inserted through
|
114
153
|
# the insert or update, and then proceeds to update that record with
|
115
154
|
# the actual large object through a prepared statement (param binding).
|
116
155
|
after_save :handle_lobs
|
117
|
-
def handle_lobs()
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
156
|
+
def handle_lobs()
|
157
|
+
if self.class.connection.kind_of?(ConnectionAdapters::IBM_DBAdapter)
|
158
|
+
# Checks that the insert or update had at least a BLOB, CLOB or XML field
|
159
|
+
self.class.connection.sql.each do |clob_sql|
|
160
|
+
if clob_sql =~ /BLOB\('(.*)'\)/i ||
|
161
|
+
clob_sql =~ /@@@IBMTEXT@@@/i ||
|
162
|
+
clob_sql =~ /@@@IBMXML@@@/i ||
|
163
|
+
clob_sql =~ /@@@IBMBINARY@@@/i
|
164
|
+
update_query = "UPDATE #{self.class.table_name} SET ("
|
165
|
+
counter = 0
|
166
|
+
values = []
|
167
|
+
params = []
|
168
|
+
# Selects only binary, text and xml columns
|
169
|
+
self.class.columns.select{|col| col.sql_type.to_s =~ /blob|binary|clob|text|xml/i }.each do |col|
|
170
|
+
if counter == 0
|
171
|
+
update_query << "#{col.name}"
|
172
|
+
else
|
173
|
+
update_query << ",#{col.name}"
|
174
|
+
end
|
175
|
+
|
176
|
+
# Add a '?' for the parameter or a NULL if the value is nil or empty
|
177
|
+
# (except for a CLOB field where '' can be a value)
|
178
|
+
if self[col.name].nil? ||
|
179
|
+
self[col.name] == {} ||
|
180
|
+
self[col.name] == [] ||
|
181
|
+
(self[col.name] == '' && !(col.sql_type.to_s =~ /text|clob/i))
|
182
|
+
params << 'NULL'
|
183
|
+
else
|
184
|
+
if (col.cast_type.is_a?(::ActiveRecord::Type::Serialized))
|
185
|
+
values << YAML.dump(self[col.name])
|
186
|
+
else
|
187
|
+
values << self[col.name]
|
188
|
+
end
|
189
|
+
params << '?'
|
190
|
+
end
|
191
|
+
counter += 1
|
192
|
+
end
|
193
|
+
|
194
|
+
# no subsequent update is required if no relevant columns are found
|
195
|
+
next if counter == 0
|
196
|
+
|
197
|
+
update_query << ") = "
|
198
|
+
# IBM_DB accepts 'SET (column) = NULL' but not (NULL),
|
199
|
+
# therefore the sql needs to be changed for a single NULL field.
|
200
|
+
if params.size==1 && params[0] == 'NULL'
|
201
|
+
update_query << "NULL"
|
202
|
+
else
|
203
|
+
update_query << "(" + params.join(',') + ")"
|
204
|
+
end
|
205
|
+
|
206
|
+
update_query << " WHERE #{self.class.primary_key} = ?"
|
207
|
+
values << self[self.class.primary_key.downcase]
|
169
208
|
|
170
209
|
begin
|
171
210
|
unless stmt = IBM_DB.prepare(self.class.connection.connection, update_query)
|
@@ -176,14 +215,15 @@ module ActiveRecord
|
|
176
215
|
raise StandardError.new('An unexpected error occurred during update of LOB/XML column')
|
177
216
|
end
|
178
217
|
end
|
179
|
-
|
218
|
+
|
219
|
+
self.class.connection.log_query(update_query,'update of LOB/XML field(s)in handle_lobs')
|
180
220
|
|
181
221
|
# rollback any failed LOB/XML field updates (and remove associated marker)
|
182
222
|
unless IBM_DB.execute(stmt, values)
|
183
223
|
error_msg = "Failed to insert/update LOB/XML field(s) due to: #{IBM_DB.getErrormsg( stmt, IBM_DB::DB_STMT )}"
|
184
224
|
self.class.connection.execute("ROLLBACK")
|
185
225
|
raise error_msg
|
186
|
-
|
226
|
+
end
|
187
227
|
rescue StandardError => error
|
188
228
|
raise error
|
189
229
|
ensure
|
@@ -194,8 +234,8 @@ module ActiveRecord
|
|
194
234
|
self.class.connection.handle_lobs_triggered = true
|
195
235
|
end # if connection.kind_of?
|
196
236
|
end # handle_lobs
|
197
|
-
private :handle_lobs
|
198
237
|
|
238
|
+
private :handle_lobs
|
199
239
|
|
200
240
|
# Establishes a connection to a specified database using the credentials provided
|
201
241
|
# with the +config+ argument. All the ActiveRecord objects will use this connection
|
@@ -208,10 +248,6 @@ module ActiveRecord
|
|
208
248
|
raise LoadError, "Failed to load IBM_DB Ruby driver."
|
209
249
|
end
|
210
250
|
|
211
|
-
#if( config.has_key?(:parameterized) && config[:parameterized] == true )
|
212
|
-
# require 'active_record/connection_adapters/ibm_db_pstmt'
|
213
|
-
# end
|
214
|
-
|
215
251
|
# Check if class TableDefinition responds to indexes method to determine if we are on AR 3 or AR 4.
|
216
252
|
# This is a interim hack ti ensure backward compatibility. To remove as we move out of AR 3 support or have a better way to determine which version of AR being run against.
|
217
253
|
checkClass = ActiveRecord::ConnectionAdapters::TableDefinition.new(self,nil)
|
@@ -326,381 +362,308 @@ module ActiveRecord
|
|
326
362
|
end
|
327
363
|
end # class Base
|
328
364
|
|
329
|
-
|
330
|
-
|
331
365
|
module ConnectionAdapters
|
332
366
|
class Column
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
367
|
+
def self.binary_to_string(value)
|
368
|
+
puts_log "binary_to_string"
|
369
|
+
# Returns a string removing the eventual BLOB scalar function
|
370
|
+
value.to_s.gsub(/"SYSIBM"."BLOB"\('(.*)'\)/i,'\1')
|
371
|
+
end
|
372
|
+
end
|
338
373
|
|
339
374
|
module Quoting
|
340
|
-
|
341
|
-
|
342
|
-
|
375
|
+
def lookup_cast_type_from_column(column) # :nodoc:
|
376
|
+
lookup_cast_type(column.sql_type_metadata.sql_type)
|
377
|
+
end
|
343
378
|
end
|
344
379
|
|
345
380
|
module Savepoints
|
346
|
-
|
347
|
-
|
348
|
-
|
381
|
+
def create_savepoint(name = current_savepoint_name)
|
382
|
+
puts_log "create_savepoint"
|
383
|
+
execute("SAVEPOINT #{name} ON ROLLBACK RETAIN CURSORS", "TRANSACTION")
|
384
|
+
end
|
349
385
|
end
|
350
386
|
|
351
387
|
|
352
388
|
module ColumnDumper
|
353
389
|
def prepare_column_options(column)
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
390
|
+
puts_log "prepare_column_options"
|
391
|
+
spec = {}
|
392
|
+
|
393
|
+
if limit = schema_limit(column)
|
394
|
+
spec[:limit] = limit
|
395
|
+
end
|
396
|
+
|
397
|
+
if precision = schema_precision(column)
|
398
|
+
spec[:precision] = precision
|
399
|
+
end
|
363
400
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
default = schema_default(column) if column.has_default?
|
369
|
-
spec[:default] = default unless default.nil?
|
401
|
+
if scale = schema_scale(column)
|
402
|
+
spec[:scale] = scale
|
403
|
+
end
|
370
404
|
|
371
|
-
|
405
|
+
default = schema_default(column) if column.has_default?
|
406
|
+
spec[:default] = default unless default.nil?
|
407
|
+
spec[:null] = 'false' unless column.null
|
372
408
|
|
373
|
-
|
374
|
-
|
375
|
-
|
409
|
+
if collation = schema_collation(column)
|
410
|
+
spec[:collation] = collation
|
411
|
+
end
|
376
412
|
|
377
|
-
|
413
|
+
spec[:comment] = column.comment.inspect if column.comment.present?
|
378
414
|
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
def schema_limit(column)
|
384
|
-
limit = column.limit unless column.bigint?
|
385
|
-
#limit.inspect if limit && limit != native_database_types[column.type][:limit]
|
386
|
-
|
387
|
-
limit.inspect if limit && limit != native_database_types[column.type.to_sym][:limit]
|
388
|
-
|
389
|
-
end
|
390
|
-
|
391
|
-
=begin
|
392
|
-
def column_spec_for_primary_key(column)
|
393
|
-
if column.bigint?
|
394
|
-
spec = { id: :bigint.inspect }
|
395
|
-
spec[:default] = schema_default(column) || 'nil' unless column.auto_increment?
|
396
|
-
else
|
397
|
-
#spec = super
|
398
|
-
end
|
399
|
-
#spec[:unsigned] = 'true' if column.unsigned?
|
400
|
-
#spec
|
401
|
-
""
|
402
|
-
end
|
403
|
-
=end
|
415
|
+
spec
|
416
|
+
end
|
404
417
|
|
405
|
-
|
418
|
+
def schema_limit(column)
|
419
|
+
puts_log "schema_limit"
|
420
|
+
limit = column.limit unless column.bigint?
|
421
|
+
limit.inspect if limit && limit != native_database_types[column.type.to_sym][:limit]
|
422
|
+
end
|
423
|
+
end #end of module ColumnDumper
|
406
424
|
|
407
425
|
module SchemaStatements
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
end
|
426
|
+
|
427
|
+
def internal_string_options_for_primary_key # :nodoc:
|
428
|
+
{ primary_key: true, null: false }
|
429
|
+
end
|
413
430
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
431
|
+
def drop_table(table_name, options={})
|
432
|
+
puts_log "drop_table - #{table_name}"
|
433
|
+
if options[:if_exists]
|
434
|
+
execute("DROP TABLE IF EXISTS #{quote_table_name(table_name)}")
|
435
|
+
else
|
436
|
+
execute("DROP TABLE #{quote_table_name(table_name)}", options)
|
437
|
+
end
|
438
|
+
end
|
418
439
|
|
419
|
-
|
420
|
-
|
421
|
-
TableDefinition.new
|
440
|
+
def create_table_definition(*args, **options)
|
441
|
+
puts_log "create_table_definition"
|
442
|
+
TableDefinition.new(self, *args, **options)
|
422
443
|
end
|
423
|
-
=end
|
424
|
-
def create_table_definition(*args, **options)
|
425
|
-
TableDefinition.new(self, *args, **options)
|
426
|
-
end
|
427
444
|
|
428
|
-
def remove_foreign_key(from_table, options_or_to_table = {})
|
429
|
-
return unless supports_foreign_keys?
|
430
|
-
|
431
|
-
if options_or_to_table.is_a?(Hash)
|
432
|
-
options = options_or_to_table
|
433
|
-
else
|
434
|
-
options = { column: foreign_key_column_for(options_or_to_table) }
|
435
|
-
end
|
436
|
-
|
437
|
-
fk_name_to_delete = options.fetch(:name) do
|
438
|
-
fk_to_delete = foreign_keys(@servertype.set_case(from_table)).detect {|fk| "#{@servertype.set_case(fk.column)}" == "#{servertype.set_case(options[:column])}"}
|
439
|
-
|
440
|
-
if fk_to_delete
|
441
|
-
fk_to_delete.name
|
442
|
-
else
|
443
|
-
raise ArgumentError, "Table '#{from_table}' has no foreign key on column '#{options[:column]}'"
|
444
|
-
end
|
445
|
-
end
|
446
|
-
|
447
|
-
at = create_alter_table from_table
|
448
|
-
at.drop_foreign_key fk_name_to_delete
|
449
|
-
|
450
|
-
execute schema_creation.accept(at)
|
451
|
-
end
|
452
445
|
end #end of Module SchemaStatements
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
# delegate :precision, :scale, :limit, :type, :sql_type, to: :sql_type_metadata, allow_nil: true
|
458
|
-
|
459
|
-
def initialize(*)
|
460
|
-
super
|
461
|
-
end
|
462
|
-
|
463
|
-
#def initialize(column_name, column_default_value, sqltype_metadata, column_nullable, table_name, default_function, collation, comment)
|
464
|
-
#super(column_name, column_default_value, sqltype_metadata, column_nullable, table_name)
|
465
|
-
#end
|
466
|
-
|
467
|
-
# Casts value (which is a String) to an appropriate instance
|
468
|
-
=begin
|
469
|
-
def type_cast(value)
|
470
|
-
# Casts the database NULL value to nil
|
471
|
-
return nil if value == 'NULL'
|
472
|
-
# Invokes parent's method for default casts
|
446
|
+
|
447
|
+
class IBM_DBColumn < ConnectionAdapters::Column # :nodoc:
|
448
|
+
def initialize(*)
|
449
|
+
puts_log "15"
|
473
450
|
super
|
474
451
|
end
|
475
|
-
=end
|
476
452
|
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
453
|
+
# Used to convert from BLOBs to Strings
|
454
|
+
def self.binary_to_string(value)
|
455
|
+
# Returns a string removing the eventual BLOB scalar function
|
456
|
+
value.to_s.gsub(/"SYSIBM"."BLOB"\('(.*)'\)/i,'\1')
|
457
|
+
end
|
483
458
|
end #class IBM_DBColumn
|
484
459
|
|
485
|
-
|
486
|
-
module ColumnMethods
|
487
|
-
|
460
|
+
module ColumnMethods
|
488
461
|
def primary_key(name, type = :primary_key, **options)
|
489
|
-
|
490
|
-
|
462
|
+
puts_log "16"
|
463
|
+
column(name, type, options.merge(primary_key: true))
|
464
|
+
end
|
491
465
|
|
492
|
-
|
493
|
-
|
494
|
-
|
466
|
+
##class Table
|
467
|
+
class Table < ActiveRecord::ConnectionAdapters::Table
|
468
|
+
include ColumnMethods
|
495
469
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
470
|
+
#Method to parse the passed arguments and create the ColumnDefinition object of the specified type
|
471
|
+
def ibm_parse_column_attributes_args(type, *args)
|
472
|
+
puts_log "ibm_parse_column_attributes_args"
|
473
|
+
options = {}
|
474
|
+
if args.last.is_a?(Hash)
|
475
|
+
options = args.delete_at(args.length-1)
|
476
|
+
end
|
477
|
+
args.each do | name |
|
478
|
+
column name,type.to_sym,options
|
479
|
+
end # end args.each
|
480
|
+
end
|
481
|
+
private :ibm_parse_column_attributes_args
|
507
482
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
def decfloat(*args)
|
533
|
-
ibm_parse_column_attributes_args('decfloat',*args)
|
534
|
-
return self
|
535
|
-
end
|
536
|
-
|
537
|
-
def graphic(*args)
|
538
|
-
ibm_parse_column_attributes_args('graphic',*args)
|
539
|
-
return self
|
540
|
-
end
|
483
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type xml
|
484
|
+
#This method is different as compared to def char (sql is being issued explicitly
|
485
|
+
#as compared to def char where method column(which will generate the sql is being called)
|
486
|
+
#in order to handle the DEFAULT and NULL option for the native XML datatype
|
487
|
+
def xml(*args )
|
488
|
+
puts_log "18"
|
489
|
+
options = {}
|
490
|
+
if args.last.is_a?(Hash)
|
491
|
+
options = args.delete_at(args.length-1)
|
492
|
+
end
|
493
|
+
sql_segment = "ALTER TABLE #{@base.quote_table_name(@table_name)} ADD COLUMN "
|
494
|
+
args.each do | name |
|
495
|
+
sql = sql_segment + " #{@base.quote_column_name(name)} xml"
|
496
|
+
@base.execute(sql,"add_xml_column")
|
497
|
+
end
|
498
|
+
return self
|
499
|
+
end
|
500
|
+
|
501
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type double
|
502
|
+
def double(*args)
|
503
|
+
puts_log "19"
|
504
|
+
ibm_parse_column_attributes_args('double',*args)
|
505
|
+
return self
|
506
|
+
end
|
541
507
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
508
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type decfloat
|
509
|
+
def decfloat(*args)
|
510
|
+
puts_log "20"
|
511
|
+
ibm_parse_column_attributes_args('decfloat',*args)
|
512
|
+
return self
|
513
|
+
end
|
546
514
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
515
|
+
def graphic(*args)
|
516
|
+
puts_log "21"
|
517
|
+
ibm_parse_column_attributes_args('graphic',*args)
|
518
|
+
return self
|
519
|
+
end
|
551
520
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
end
|
557
|
-
alias_method :character, :char
|
521
|
+
def vargraphic(*args)
|
522
|
+
puts_log "22"
|
523
|
+
ibm_parse_column_attributes_args('vargraphic',*args)
|
524
|
+
return self
|
558
525
|
end
|
559
526
|
|
560
|
-
|
561
|
-
|
562
|
-
|
527
|
+
def bigint(*args)
|
528
|
+
puts_log "23"
|
529
|
+
ibm_parse_column_attributes_args('bigint',*args)
|
530
|
+
return self
|
531
|
+
end
|
563
532
|
|
564
|
-
|
565
|
-
|
533
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type char [character]
|
534
|
+
def char(*args)
|
535
|
+
puts_log "24"
|
536
|
+
ibm_parse_column_attributes_args('char',*args)
|
537
|
+
return self
|
538
|
+
end
|
539
|
+
alias_method :character, :char
|
566
540
|
|
567
|
-
|
568
|
-
@ar3 = false
|
569
|
-
else
|
570
|
-
@ar3 = true
|
571
|
-
end
|
541
|
+
end # end of class Table
|
572
542
|
|
573
|
-
|
574
|
-
|
575
|
-
@indexes = {}
|
576
|
-
@base = base
|
577
|
-
@temporary = temporary
|
578
|
-
@options = options
|
579
|
-
@name = name
|
580
|
-
@foreign_keys = {}
|
581
|
-
end
|
582
|
-
=end
|
583
|
-
|
584
|
-
def initialize(conn, name, temporary = false, options = nil, as = nil, comment: nil)
|
585
|
-
@connection = conn
|
586
|
-
@columns_hash = {}
|
587
|
-
@indexes = []
|
588
|
-
@foreign_keys = []
|
589
|
-
@primary_keys = nil
|
590
|
-
@temporary = temporary
|
591
|
-
@options = options
|
592
|
-
@as = as
|
593
|
-
@name = name
|
594
|
-
@comment = comment
|
595
|
-
##
|
596
|
-
#@base = base
|
597
|
-
end
|
598
|
-
|
599
|
-
def primary_keys(name = nil) # :nodoc:
|
600
|
-
@primary_keys = PrimaryKeyDefinition.new(name) if name
|
601
|
-
@primary_keys
|
602
|
-
end
|
543
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
544
|
+
include ColumnMethods
|
603
545
|
|
604
|
-
|
605
|
-
|
606
|
-
|
546
|
+
def native
|
547
|
+
puts_log "25"
|
548
|
+
@base.native_database_types
|
549
|
+
end
|
607
550
|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
args.each do | name |
|
615
|
-
column(name,type,options)
|
616
|
-
end
|
551
|
+
#Method to parse the passed arguments and create the ColumnDefinition object of the specified type
|
552
|
+
def ibm_parse_column_attributes_args(type, *args)
|
553
|
+
puts_log "26"
|
554
|
+
options = {}
|
555
|
+
if args.last.is_a?(Hash)
|
556
|
+
options = args.delete_at(args.length-1)
|
617
557
|
end
|
618
|
-
|
619
|
-
|
620
|
-
#Method to support the new syntax of rails 2.0 migrations for columns of type xml
|
621
|
-
def xml(*args )
|
622
|
-
ibm_parse_column_attributes_args('xml', *args)
|
623
|
-
return self
|
558
|
+
args.each do | name |
|
559
|
+
column(name,type,options)
|
624
560
|
end
|
561
|
+
end
|
562
|
+
private :ibm_parse_column_attributes_args
|
625
563
|
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
564
|
+
#Method to support the new syntax of rails 2.0 migrations for columns of type xml
|
565
|
+
def xml(*args )
|
566
|
+
puts_log "27"
|
567
|
+
ibm_parse_column_attributes_args('xml', *args)
|
568
|
+
return self
|
569
|
+
end
|
631
570
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
571
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type double
|
572
|
+
def double(*args)
|
573
|
+
puts_log "28"
|
574
|
+
ibm_parse_column_attributes_args('double',*args)
|
575
|
+
return self
|
576
|
+
end
|
637
577
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
578
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type decfloat
|
579
|
+
def decfloat(*args)
|
580
|
+
puts_log "29"
|
581
|
+
ibm_parse_column_attributes_args('decfloat',*args)
|
582
|
+
return self
|
583
|
+
end
|
642
584
|
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
585
|
+
def graphic(*args)
|
586
|
+
puts_log "30"
|
587
|
+
ibm_parse_column_attributes_args('graphic',*args)
|
588
|
+
return self
|
589
|
+
end
|
647
590
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
591
|
+
def vargraphic(*args)
|
592
|
+
puts_log "31"
|
593
|
+
ibm_parse_column_attributes_args('vargraphic',*args)
|
594
|
+
return self
|
595
|
+
end
|
652
596
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
597
|
+
def bigint(*args)
|
598
|
+
puts_log "32"
|
599
|
+
ibm_parse_column_attributes_args('bigint',*args)
|
600
|
+
return self
|
601
|
+
end
|
602
|
+
|
603
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type char [character]
|
604
|
+
def char(*args)
|
605
|
+
puts_log "33"
|
606
|
+
ibm_parse_column_attributes_args('char',*args)
|
607
|
+
return self
|
608
|
+
end
|
609
|
+
alias_method :character, :char
|
610
|
+
|
611
|
+
# Overrides the abstract adapter in order to handle
|
612
|
+
# the DEFAULT option for the native XML datatype
|
613
|
+
def column(name, type, index: nil, **options)
|
614
|
+
puts_log "34 column"
|
615
|
+
name = name.to_s
|
616
|
+
type = type.to_sym if type
|
617
|
+
|
618
|
+
if @columns_hash[name]
|
619
|
+
if @columns_hash[name].primary_key?
|
620
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
621
|
+
else
|
622
|
+
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
623
|
+
end
|
624
|
+
end
|
659
625
|
|
660
|
-
|
661
|
-
|
662
|
-
def column(name, type, options ={})
|
663
|
-
# construct a column definition where @base is adaptor instance
|
664
|
-
column = ColumnDefinition.new(name, type)
|
626
|
+
# construct a column definition where @base is adaptor instance
|
627
|
+
column = new_column_definition(name, type, **options)
|
665
628
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
end
|
681
|
-
return sql
|
629
|
+
# DB2 does not accept DEFAULT NULL option for XML
|
630
|
+
# for table create, but does accept nullable option
|
631
|
+
unless type.to_s == 'xml'
|
632
|
+
column.null = options[:null]
|
633
|
+
column.default = options[:default]
|
634
|
+
else
|
635
|
+
column.null = options[:null]
|
636
|
+
# Override column object's (instance of ColumnDefinition structure)
|
637
|
+
# to_s which is expected to return the create_table SQL fragment
|
638
|
+
# and bypass DEFAULT NULL option while still appending NOT NULL
|
639
|
+
def column.to_s
|
640
|
+
sql = "#{base.quote_column_name(name)} #{type}"
|
641
|
+
unless self.null == nil
|
642
|
+
sql << " NOT NULL" if (self.null == false)
|
682
643
|
end
|
644
|
+
return sql
|
683
645
|
end
|
646
|
+
end
|
684
647
|
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
648
|
+
column.scale = options[:scale] if options[:scale]
|
649
|
+
column.precision = options[:precision] if options[:precision]
|
650
|
+
# append column's limit option and yield native limits
|
651
|
+
if options[:limit]
|
652
|
+
column.limit = options[:limit]
|
653
|
+
elsif @base.native_database_types[type.to_sym]
|
654
|
+
column.limit = @base.native_database_types[type.to_sym][:limit] if @base.native_database_types[type.to_sym].has_key? :limit
|
655
|
+
end
|
693
656
|
|
694
|
-
|
695
|
-
|
696
|
-
|
657
|
+
unless @columns.nil? or @columns.include? column
|
658
|
+
@columns << column
|
659
|
+
end
|
697
660
|
|
698
|
-
|
661
|
+
@columns_hash[name] = column
|
699
662
|
|
700
|
-
|
701
|
-
end
|
663
|
+
return self
|
702
664
|
end
|
703
|
-
|
665
|
+
end #end of class TableDefinition
|
666
|
+
end #end of module ColumnMethods
|
704
667
|
|
705
668
|
# The IBM_DB Adapter requires the native Ruby driver (ibm_db)
|
706
669
|
# for IBM data servers (ibm_db.so).
|
@@ -743,24 +706,36 @@ module ActiveRecord
|
|
743
706
|
'IBM_DB'
|
744
707
|
end
|
745
708
|
|
746
|
-
class
|
747
|
-
|
709
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
710
|
+
private
|
711
|
+
def dealloc(stmt)
|
712
|
+
#stmt.close unless stmt.closed?
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
def build_statement_pool
|
717
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
748
718
|
end
|
749
719
|
|
750
720
|
def initialize(connection, ar3, logger, config, conn_options)
|
751
721
|
# Caching database connection configuration (+connect+ or +reconnect+ support)\
|
752
|
-
|
722
|
+
@config = config
|
753
723
|
@connection = connection
|
754
724
|
@isAr3 = ar3
|
755
725
|
@conn_options = conn_options
|
756
726
|
@database = config[:database]
|
757
727
|
@username = config[:username]
|
758
728
|
@password = config[:password]
|
729
|
+
@debug = config[:debug]
|
759
730
|
if config.has_key?(:host)
|
760
731
|
@host = config[:host]
|
761
732
|
@port = config[:port] || 50000 # default port
|
762
733
|
end
|
763
|
-
|
734
|
+
if config.has_key?(:schema)
|
735
|
+
@schema = config[:schema]
|
736
|
+
else
|
737
|
+
@schema = config[:username]
|
738
|
+
end
|
764
739
|
@security = config[:security] || nil
|
765
740
|
@authentication = config[:authentication] || nil
|
766
741
|
@timeout = config[:timeout] || 0 # default timeout value is 0
|
@@ -800,7 +775,7 @@ module ActiveRecord
|
|
800
775
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
801
776
|
when /10/
|
802
777
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
803
|
-
|
778
|
+
when /11/
|
804
779
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
805
780
|
when /12/
|
806
781
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
@@ -818,6 +793,7 @@ module ActiveRecord
|
|
818
793
|
warn "Forcing servertype to LUW: DBMS name could not be retrieved. Check if your client version is of the right level"
|
819
794
|
@servertype = IBM_DB2_LUW.new(self, @isAr3)
|
820
795
|
end
|
796
|
+
@database_version = server_info.DBMS_VER
|
821
797
|
else
|
822
798
|
error_msg = IBM_DB.getErrormsg( @connection, IBM_DB::DB_CONN )
|
823
799
|
IBM_DB.close( @connection )
|
@@ -857,8 +833,25 @@ module ActiveRecord
|
|
857
833
|
end
|
858
834
|
end
|
859
835
|
|
836
|
+
def get_database_version
|
837
|
+
@database_version
|
838
|
+
end
|
839
|
+
|
840
|
+
def prepared_statements?
|
841
|
+
puts_log "prepared_statements?"
|
842
|
+
prepare = @prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
843
|
+
puts_log "prepare = #{prepare}"
|
844
|
+
prepare
|
845
|
+
end
|
846
|
+
alias :prepared_statements :prepared_statements?
|
847
|
+
|
848
|
+
def bind_params_length
|
849
|
+
999
|
850
|
+
end
|
851
|
+
|
860
852
|
# Optional connection attribute: database name space qualifier
|
861
853
|
def schema=(name)
|
854
|
+
puts_log "schema="
|
862
855
|
unless name == @schema
|
863
856
|
@schema = name
|
864
857
|
@servertype.set_schema(@schema)
|
@@ -867,6 +860,7 @@ module ActiveRecord
|
|
867
860
|
|
868
861
|
# Optional connection attribute: authenticated application user
|
869
862
|
def app_user=(name)
|
863
|
+
puts_log "app_user="
|
870
864
|
unless name == @app_user
|
871
865
|
option = {IBM_DB::SQL_ATTR_INFO_USERID => "#{name}"}
|
872
866
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -877,6 +871,7 @@ module ActiveRecord
|
|
877
871
|
|
878
872
|
# Optional connection attribute: OS account (client workstation)
|
879
873
|
def account=(name)
|
874
|
+
puts_log "account="
|
880
875
|
unless name == @account
|
881
876
|
option = {IBM_DB::SQL_ATTR_INFO_ACCTSTR => "#{name}"}
|
882
877
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -887,6 +882,7 @@ module ActiveRecord
|
|
887
882
|
|
888
883
|
# Optional connection attribute: application name
|
889
884
|
def application=(name)
|
885
|
+
puts_log "application="
|
890
886
|
unless name == @application
|
891
887
|
option = {IBM_DB::SQL_ATTR_INFO_APPLNAME => "#{name}"}
|
892
888
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -897,6 +893,7 @@ module ActiveRecord
|
|
897
893
|
|
898
894
|
# Optional connection attribute: client workstation name
|
899
895
|
def workstation=(name)
|
896
|
+
puts_log "workstation="
|
900
897
|
unless name == @workstation
|
901
898
|
option = {IBM_DB::SQL_ATTR_INFO_WRKSTNNAME => "#{name}"}
|
902
899
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -906,61 +903,101 @@ module ActiveRecord
|
|
906
903
|
end
|
907
904
|
|
908
905
|
def self.visitor_for(pool)
|
906
|
+
puts_log "visitor_for"
|
909
907
|
Arel::Visitors::IBM_DB.new(pool)
|
910
908
|
end
|
911
909
|
|
912
|
-
|
910
|
+
#Check Arel version
|
913
911
|
begin
|
914
912
|
@arelVersion = Arel::VERSION.to_i
|
915
913
|
rescue
|
916
914
|
@arelVersion = 0
|
917
915
|
end
|
918
916
|
if(@arelVersion < 6 )
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
end
|
924
|
-
else
|
925
|
-
arel
|
917
|
+
def to_sql(arel, binds = [])
|
918
|
+
if arel.respond_to?(:ast)
|
919
|
+
visitor.accept(arel.ast) do
|
920
|
+
quote(*binds.shift.reverse)
|
926
921
|
end
|
922
|
+
else
|
923
|
+
arel
|
927
924
|
end
|
928
|
-
|
925
|
+
end
|
926
|
+
end
|
927
|
+
|
929
928
|
# This adapter supports migrations.
|
930
929
|
# Current limitations:
|
931
930
|
# +rename_column+ is not currently supported by the IBM data servers
|
932
931
|
# +remove_column+ is not currently supported by the DB2 for zOS data server
|
933
932
|
# Tables containing columns of XML data type do not support +remove_column+
|
934
933
|
def supports_migrations?
|
934
|
+
puts_log "supports_migrations?"
|
935
935
|
true
|
936
936
|
end
|
937
937
|
|
938
938
|
def supports_foreign_keys?
|
939
|
+
puts_log "supports_foreign_keys?"
|
939
940
|
true
|
940
941
|
end
|
941
942
|
|
942
943
|
def supports_datetime_with_precision?
|
943
|
-
|
944
|
+
puts_log "supports_datetime_with_precision?"
|
945
|
+
true
|
944
946
|
end
|
945
947
|
|
946
948
|
# This Adapter supports DDL transactions.
|
947
949
|
# This means CREATE TABLE and other DDL statements can be carried out as a transaction.
|
948
950
|
# That is the statements executed can be ROLLED BACK in case of any error during the process.
|
949
951
|
def supports_ddl_transactions?
|
952
|
+
puts_log "supports_ddl_transactions?"
|
953
|
+
true
|
954
|
+
end
|
955
|
+
|
956
|
+
def supports_explain?
|
957
|
+
puts_log "supports_explain?"
|
958
|
+
true
|
959
|
+
end
|
960
|
+
|
961
|
+
def supports_lazy_transactions?
|
962
|
+
puts_log "supports_lazy_transactions?"
|
963
|
+
true
|
964
|
+
end
|
965
|
+
|
966
|
+
def supports_comments?
|
967
|
+
true
|
968
|
+
end
|
969
|
+
|
970
|
+
def supports_views?
|
950
971
|
true
|
951
972
|
end
|
952
973
|
|
953
974
|
def log_query(sql, name) #:nodoc:
|
975
|
+
puts_log "log_query"
|
954
976
|
# Used by handle_lobs
|
955
977
|
log(sql,name){}
|
956
978
|
end
|
957
979
|
|
980
|
+
def supports_partitioned_indexes?
|
981
|
+
true
|
982
|
+
end
|
983
|
+
|
984
|
+
def puts_log (val)
|
985
|
+
begin
|
986
|
+
# puts val
|
987
|
+
rescue
|
988
|
+
end
|
989
|
+
if @debug == true
|
990
|
+
log(" IBM_DB = #{val}", "TRANSACTION"){}
|
991
|
+
end
|
992
|
+
end
|
993
|
+
|
958
994
|
#==============================================
|
959
995
|
# CONNECTION MANAGEMENT
|
960
996
|
#==============================================
|
961
997
|
|
962
998
|
# Tests the connection status
|
963
999
|
def active?
|
1000
|
+
puts_log "active?"
|
964
1001
|
IBM_DB.active @connection
|
965
1002
|
rescue
|
966
1003
|
false
|
@@ -969,6 +1006,7 @@ module ActiveRecord
|
|
969
1006
|
# Private method used by +reconnect!+.
|
970
1007
|
# It connects to the database with the initially provided credentials
|
971
1008
|
def connect
|
1009
|
+
puts_log "connect"
|
972
1010
|
# If the type of connection is net based
|
973
1011
|
if(@username.nil? || @password.nil?)
|
974
1012
|
raise ArgumentError, "Username/Password cannot be nil"
|
@@ -1006,6 +1044,7 @@ module ActiveRecord
|
|
1006
1044
|
|
1007
1045
|
# Closes the current connection and opens a new one
|
1008
1046
|
def reconnect!
|
1047
|
+
puts_log "reconnect!"
|
1009
1048
|
disconnect!
|
1010
1049
|
connect
|
1011
1050
|
end
|
@@ -1016,100 +1055,50 @@ module ActiveRecord
|
|
1016
1055
|
# * true if succesfull
|
1017
1056
|
# * false if the connection is already closed
|
1018
1057
|
# * nil if an error is raised
|
1058
|
+
puts_log "disconnect!"
|
1019
1059
|
return nil if @connection.nil? || @connection == false
|
1020
1060
|
IBM_DB.close(@connection) rescue nil
|
1061
|
+
@connection = nil
|
1062
|
+
reset_transaction
|
1021
1063
|
end
|
1022
1064
|
|
1023
1065
|
#==============================================
|
1024
1066
|
# DATABASE STATEMENTS
|
1025
1067
|
#==============================================
|
1026
1068
|
|
1027
|
-
def create_table(name,
|
1069
|
+
def create_table(name, id: :primary_key, primary_key: nil, force: nil, **options)
|
1070
|
+
puts_log "create_table name=#{name}, id=#{id}, primary_key=#{primary_key}, force=#{force}"
|
1071
|
+
puts_log "create_table Options = #{options}"
|
1072
|
+
puts_log "primary_key_prefix_type = #{ActiveRecord::Base.primary_key_prefix_type}"
|
1073
|
+
puts_log caller
|
1028
1074
|
@servertype.setup_for_lob_table
|
1029
1075
|
#Table definition is complete only when a unique index is created on the primarykey column for DB2 V8 on zOS
|
1030
1076
|
|
1031
1077
|
#create index on id column if options[:id] is nil or id ==true
|
1032
1078
|
#else check if options[:primary_key]is not nil then create an unique index on that column
|
1033
|
-
if !
|
1034
|
-
if (!
|
1035
|
-
|
1036
|
-
elsif !
|
1037
|
-
|
1079
|
+
if !id.nil? || !primary_key.nil?
|
1080
|
+
if (!id.nil? && id == true)
|
1081
|
+
@servertype.create_index_after_table(name,"id")
|
1082
|
+
elsif !primary_key.nil?
|
1083
|
+
@servertype.create_index_after_table(name,primary_key.to_s)
|
1038
1084
|
end
|
1039
1085
|
else
|
1040
|
-
|
1086
|
+
@servertype.create_index_after_table(name,"id")
|
1041
1087
|
end
|
1042
|
-
super(name, options)
|
1043
|
-
end
|
1044
|
-
|
1045
|
-
# Returns an array of hashes with the column names as keys and
|
1046
|
-
# column values as values. +sql+ is the select query,
|
1047
|
-
# and +name+ is an optional description for logging
|
1048
|
-
def prepared_select(sql_param_hash, name = nil)
|
1049
|
-
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
1050
1088
|
|
1051
|
-
|
1052
|
-
#
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
begin
|
1057
|
-
results = @servertype.select(pstmt)
|
1058
|
-
rescue StandardError => fetch_error # Handle driver fetch errors
|
1059
|
-
error_msg = IBM_DB.getErrormsg(pstmt, IBM_DB::DB_STMT )
|
1060
|
-
if error_msg && !error_msg.empty?
|
1061
|
-
raise StatementInvalid,"Failed to retrieve data: #{error_msg}"
|
1062
|
-
else
|
1063
|
-
error_msg = "An unexpected error occurred during data retrieval"
|
1064
|
-
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
1065
|
-
raise error_msg
|
1066
|
-
end
|
1067
|
-
ensure
|
1068
|
-
# Ensures to free the resources associated with the statement
|
1069
|
-
IBM_DB.free_stmt(pstmt) if pstmt
|
1070
|
-
end
|
1089
|
+
#Just incase if id holds any other data type other than primary_key we override it,
|
1090
|
+
#otherwise it misses "GENERATED BY DEFAULT AS IDENTITY (START WITH 1000)"
|
1091
|
+
if !id.nil? && id != false && primary_key.nil? && ActiveRecord::Base.primary_key_prefix_type.nil?
|
1092
|
+
primary_key = :id
|
1093
|
+
options[:auto_increment] = true if options[:auto_increment].nil? and (id == :integer or id == :bigint)
|
1071
1094
|
end
|
1072
|
-
# The array of record hashes is returned
|
1073
|
-
results
|
1074
|
-
end
|
1075
1095
|
|
1076
|
-
|
1077
|
-
# column values as values. +sql+ is the select query,
|
1078
|
-
# and +name+ is an optional description for logging
|
1079
|
-
def prepared_select_values(sql_param_hash, name = nil)
|
1080
|
-
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
1081
|
-
results = []
|
1082
|
-
# Invokes the method +prepare+ in order prepare the SQL
|
1083
|
-
# IBM_DB.Statement is returned from which the statement is executed and results fetched
|
1084
|
-
pstmt = prepare(sql_param_hash["sqlSegment"], name)
|
1085
|
-
if(execute_prepared_stmt(pstmt, sql_param_hash["paramArray"]))
|
1086
|
-
begin
|
1087
|
-
results = @servertype.select_rows(sql_param_hash["sqlSegment"], name, pstmt, results)
|
1088
|
-
if results
|
1089
|
-
return results.map { |v| v[0] }
|
1090
|
-
else
|
1091
|
-
nil
|
1092
|
-
end
|
1093
|
-
rescue StandardError => fetch_error # Handle driver fetch errors
|
1094
|
-
error_msg = IBM_DB.getErrormsg(pstmt, IBM_DB::DB_STMT )
|
1095
|
-
if error_msg && !error_msg.empty?
|
1096
|
-
raise StatementInvalid,"Failed to retrieve data: #{error_msg}"
|
1097
|
-
else
|
1098
|
-
error_msg = "An unexpected error occurred during data retrieval"
|
1099
|
-
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
1100
|
-
raise error_msg
|
1101
|
-
end
|
1102
|
-
ensure
|
1103
|
-
# Ensures to free the resources associated with the statement
|
1104
|
-
IBM_DB.free_stmt(pstmt) if pstmt
|
1105
|
-
end
|
1106
|
-
end
|
1107
|
-
# The array of record hashes is returned
|
1108
|
-
results
|
1096
|
+
super(name, id: id, primary_key: primary_key, force: force, **options)
|
1109
1097
|
end
|
1110
1098
|
|
1111
1099
|
#Calls the servertype select method to fetch the data
|
1112
1100
|
def fetch_data(stmt)
|
1101
|
+
puts_log "fetch_data"
|
1113
1102
|
if(stmt)
|
1114
1103
|
begin
|
1115
1104
|
return @servertype.select(stmt)
|
@@ -1118,33 +1107,63 @@ module ActiveRecord
|
|
1118
1107
|
if error_msg && !error_msg.empty?
|
1119
1108
|
raise StatementInvalid,"Failed to retrieve data: #{error_msg}"
|
1120
1109
|
else
|
1121
|
-
error_msg = "An unexpected error occurred during data retrieval"
|
1122
1110
|
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
1123
1111
|
raise error_msg
|
1124
1112
|
end
|
1125
1113
|
ensure
|
1126
1114
|
# Ensures to free the resources associated with the statement
|
1127
|
-
|
1115
|
+
if stmt
|
1116
|
+
puts_log "Free Statement #{stmt}"
|
1117
|
+
IBM_DB.free_stmt(stmt)
|
1118
|
+
end
|
1128
1119
|
end
|
1129
1120
|
end
|
1130
1121
|
end
|
1131
1122
|
|
1132
|
-
def select(sql, name = nil, binds = [])
|
1123
|
+
def select(sql, name = nil, binds = [], prepare: false, async: false)
|
1124
|
+
puts_log "select #{sql}"
|
1125
|
+
puts_log "prepare = #{prepare}"
|
1126
|
+
|
1133
1127
|
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"
|
1134
|
-
|
1128
|
+
begin
|
1129
|
+
sql.gsub( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
|
1130
|
+
rescue
|
1131
|
+
# ...
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
if async && async_enabled?
|
1135
|
+
if current_transaction.joinable?
|
1136
|
+
raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
future_result = async.new(
|
1140
|
+
pool,
|
1141
|
+
sql,
|
1142
|
+
name,
|
1143
|
+
binds,
|
1144
|
+
prepare: prepare,
|
1145
|
+
)
|
1146
|
+
if supports_concurrent_connections? && current_transaction.closed?
|
1147
|
+
future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
|
1148
|
+
else
|
1149
|
+
future_result.execute!(self)
|
1150
|
+
end
|
1151
|
+
return future_result
|
1152
|
+
end
|
1135
1153
|
|
1136
1154
|
results = []
|
1137
1155
|
|
1138
1156
|
if(binds.nil? || binds.empty?)
|
1139
1157
|
stmt = execute(sql, name)
|
1140
1158
|
else
|
1141
|
-
stmt =
|
1159
|
+
stmt = exec_query_ret_stmt(sql, name, binds, prepare)
|
1142
1160
|
end
|
1143
1161
|
|
1144
1162
|
cols = IBM_DB.resultCols(stmt)
|
1145
1163
|
|
1146
1164
|
if( stmt )
|
1147
1165
|
results = fetch_data(stmt)
|
1166
|
+
puts_log "Results = #{results}"
|
1148
1167
|
end
|
1149
1168
|
|
1150
1169
|
if(@isAr3)
|
@@ -1154,57 +1173,96 @@ module ActiveRecord
|
|
1154
1173
|
end
|
1155
1174
|
end
|
1156
1175
|
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1176
|
+
def translate_exception(exception, message:, sql:, binds:)
|
1177
|
+
error_msg1 = /SQL0803N One or more values in the INSERT statement, UPDATE statement, or foreign key update caused by a DELETE statement are not valid because the primary key, unique constraint or unique index identified by .* constrains table .* from having duplicate values for the index key/
|
1178
|
+
error_msg2 = /SQL0204N .* is an undefined name/
|
1179
|
+
error_msg3 = /SQL0413N Overflow occurred during numeric data type conversion/
|
1180
|
+
error_msg4 = /SQL0407N Assignment of a NULL value to a NOT NULL column .* is not allowed/
|
1181
|
+
error_msg5 = /SQL0530N The insert or update value of the FOREIGN KEY .* is not equal to any value of the parent key of the parent table/
|
1182
|
+
error_msg6 = /SQL0532N A parent row cannot be deleted because the relationship .* restricts the deletion/
|
1183
|
+
error_msg7 = /SQL0433N Value .* is too long/
|
1184
|
+
error_msg8 = /CLI0109E String data right truncation/
|
1185
|
+
if !error_msg1.match(message).nil?
|
1186
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
1187
|
+
elsif !error_msg2.match(message).nil?
|
1188
|
+
ArgumentError.new(message)
|
1189
|
+
elsif !error_msg3.match(message).nil?
|
1190
|
+
RangeError.new(message, sql: sql, binds: binds)
|
1191
|
+
elsif !error_msg4.match(message).nil?
|
1192
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
1193
|
+
elsif !error_msg5.match(message).nil? or !error_msg6.match(message).nil?
|
1194
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
1195
|
+
elsif !error_msg7.match(message).nil? or !error_msg8.match(message).nil?
|
1196
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
1197
|
+
elsif exception.message.match?(/called on a closed database/i)
|
1198
|
+
ConnectionNotEstablished.new(exception)
|
1199
|
+
else
|
1200
|
+
super
|
1172
1201
|
end
|
1202
|
+
end
|
1173
1203
|
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1204
|
+
def build_truncate_statement(table_name)
|
1205
|
+
puts_log "build_truncate_statement"
|
1206
|
+
"DELETE FROM #{quote_table_name(table_name)}"
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
def build_fixture_statements(fixture_set)
|
1210
|
+
fixture_set.flat_map do |table_name, fixtures|
|
1211
|
+
next if fixtures.empty?
|
1212
|
+
fixtures.map { |fixture| build_fixture_sql([fixture], table_name) }
|
1213
|
+
end.compact
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
def build_fixture_sql(fixtures, table_name)
|
1217
|
+
puts_log "build_fixture_sql"
|
1218
|
+
columns = schema_cache.columns_hash(table_name)
|
1219
|
+
|
1220
|
+
values_list = fixtures.map do |fixture|
|
1221
|
+
fixture = fixture.stringify_keys
|
1222
|
+
fixture = fixture.transform_keys(&:downcase)
|
1223
|
+
|
1224
|
+
unknown_columns = fixture.keys - columns.keys
|
1225
|
+
if unknown_columns.any?
|
1226
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
columns.map do |name, column|
|
1230
|
+
if fixture.key?(name)
|
1231
|
+
type = lookup_cast_type_from_column(column)
|
1232
|
+
with_yaml_fallback(type.serialize(fixture[name]))
|
1182
1233
|
else
|
1183
|
-
|
1184
|
-
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
1185
|
-
raise error_msg
|
1234
|
+
default_insert_value(column)
|
1186
1235
|
end
|
1187
|
-
ensure
|
1188
|
-
# Ensures to free the resources associated with the statement
|
1189
|
-
IBM_DB.free_stmt(stmt) if stmt
|
1190
1236
|
end
|
1191
1237
|
end
|
1192
|
-
# The array of record hashes is returned
|
1193
|
-
results
|
1194
|
-
end
|
1195
1238
|
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1239
|
+
table = Arel::Table.new(table_name)
|
1240
|
+
manager = Arel::InsertManager.new
|
1241
|
+
manager.into(table)
|
1242
|
+
|
1243
|
+
if values_list.size == 1
|
1244
|
+
values = values_list.shift
|
1245
|
+
new_values = []
|
1246
|
+
columns.each_key.with_index { |column, i|
|
1247
|
+
unless values[i].equal?(DEFAULT_INSERT_VALUE)
|
1248
|
+
new_values << values[i]
|
1249
|
+
manager.columns << table[column]
|
1250
|
+
end
|
1251
|
+
}
|
1252
|
+
values_list << new_values
|
1253
|
+
else
|
1254
|
+
columns.each_key { |column| manager.columns << table[column] }
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
manager.values = manager.create_values_list(values_list)
|
1258
|
+
visitor.compile(manager.ast)
|
1259
|
+
end
|
1203
1260
|
|
1204
1261
|
#inserts values from fixtures
|
1205
1262
|
#overridden to handle LOB's fixture insertion, as, in normal inserts callbacks are triggered but during fixture insertion callbacks are not triggered
|
1206
1263
|
#hence only markers like @@@IBMBINARY@@@ will be inserted and are not updated to actual data
|
1207
1264
|
def insert_fixture(fixture, table_name)
|
1265
|
+
puts_log "insert_fixture = #{fixture}"
|
1208
1266
|
if(fixture.respond_to?(:keys))
|
1209
1267
|
insert_query = "INSERT INTO #{quote_table_name(table_name)} ( #{fixture.keys.join(', ')})"
|
1210
1268
|
else
|
@@ -1253,7 +1311,6 @@ module ActiveRecord
|
|
1253
1311
|
end
|
1254
1312
|
end
|
1255
1313
|
|
1256
|
-
#log_query(insert_query,'fixture insert')
|
1257
1314
|
log(insert_query,'fixture insert') do
|
1258
1315
|
unless IBM_DB.execute(stmt, insert_values)
|
1259
1316
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
@@ -1266,19 +1323,24 @@ module ActiveRecord
|
|
1266
1323
|
end
|
1267
1324
|
|
1268
1325
|
def empty_insert_statement_value(pkey)
|
1269
|
-
|
1326
|
+
if !pkey.nil?
|
1327
|
+
"(#{pkey}) VALUES (DEFAULT)"
|
1328
|
+
else
|
1329
|
+
raise ArgumentError, "Empty Insert Statement not allowed in DB2"
|
1330
|
+
end
|
1270
1331
|
end
|
1271
1332
|
|
1272
1333
|
# Perform an insert and returns the last ID generated.
|
1273
1334
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
1274
1335
|
# and retrieved by the +last_generated_id+ method.
|
1275
1336
|
def insert_direct(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
1337
|
+
puts_log "insert_direct"
|
1276
1338
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1277
1339
|
@sql = []
|
1278
1340
|
@handle_lobs_triggered = false
|
1279
1341
|
end
|
1280
1342
|
|
1281
|
-
|
1343
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1282
1344
|
|
1283
1345
|
if stmt = execute(sql, name)
|
1284
1346
|
begin
|
@@ -1292,20 +1354,23 @@ module ActiveRecord
|
|
1292
1354
|
end
|
1293
1355
|
|
1294
1356
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds=[])
|
1357
|
+
puts_log "insert Binds = #{binds}"
|
1295
1358
|
if(@arelVersion < 6)
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1359
|
+
sql, binds = [to_sql(arel), binds]
|
1360
|
+
else
|
1361
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
1362
|
+
end
|
1300
1363
|
|
1364
|
+
puts_log "Binds 2 = #{binds}"
|
1365
|
+
puts_log "SQL = #{sql}"
|
1301
1366
|
#unless IBM_DBAdapter.respond_to?(:exec_insert)
|
1302
1367
|
if binds.nil? || binds.empty?
|
1303
1368
|
return insert_direct(sql, name, pk, id_value, sequence_name)
|
1304
1369
|
end
|
1305
1370
|
|
1306
|
-
|
1371
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1307
1372
|
|
1308
|
-
if stmt =
|
1373
|
+
if stmt = exec_insert_db2(sql, name, binds)
|
1309
1374
|
begin
|
1310
1375
|
@sql << sql
|
1311
1376
|
return id_value || @servertype.last_generated_id(stmt)
|
@@ -1315,18 +1380,36 @@ module ActiveRecord
|
|
1315
1380
|
end
|
1316
1381
|
end
|
1317
1382
|
|
1383
|
+
def exec_insert_db2(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
1384
|
+
puts_log "exec_insert_db2"
|
1385
|
+
sql, binds = sql_for_insert(sql, pk, binds)
|
1386
|
+
exec_query_ret_stmt(sql, name, binds, prepare = false)
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
def last_inserted_id(result)
|
1390
|
+
puts_log "last_inserted_id"
|
1391
|
+
return result
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) # :nodoc:
|
1395
|
+
puts_log "exec_insert"
|
1396
|
+
value = insert(sql)
|
1397
|
+
return value
|
1398
|
+
end
|
1399
|
+
|
1318
1400
|
# Praveen
|
1319
1401
|
# Performs an insert using the prepared statement and returns the last ID generated.
|
1320
1402
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
1321
1403
|
# and retrieved by the +last_generated_id+ method.
|
1322
1404
|
def prepared_insert(pstmt, param_array = nil, id_value = nil)
|
1405
|
+
puts_log "prepared_insert"
|
1323
1406
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1324
1407
|
@sql = []
|
1325
1408
|
@sql_parameter_values = []
|
1326
1409
|
@handle_lobs_triggered = false
|
1327
1410
|
end
|
1328
1411
|
|
1329
|
-
|
1412
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1330
1413
|
|
1331
1414
|
begin
|
1332
1415
|
if execute_prepared_stmt(pstmt, param_array)
|
@@ -1345,6 +1428,7 @@ module ActiveRecord
|
|
1345
1428
|
# Prepares and logs +sql+ commands and
|
1346
1429
|
# returns a +IBM_DB.Statement+ object.
|
1347
1430
|
def prepare(sql,name = nil)
|
1431
|
+
puts_log "prepare"
|
1348
1432
|
# The +log+ method is defined in the parent class +AbstractAdapter+
|
1349
1433
|
@prepared_sql = sql
|
1350
1434
|
log(sql,name) do
|
@@ -1356,17 +1440,15 @@ module ActiveRecord
|
|
1356
1440
|
#Executes the prepared statement
|
1357
1441
|
#ReturnsTrue on success and False on Failure
|
1358
1442
|
def execute_prepared_stmt(pstmt, param_array = nil)
|
1443
|
+
puts_log "execute_prepared_stmt"
|
1444
|
+
puts_log "Param array = #{param_array}"
|
1359
1445
|
if !param_array.nil? && param_array.size < 1
|
1360
1446
|
param_array = nil
|
1361
1447
|
end
|
1362
1448
|
|
1363
1449
|
if( !IBM_DB.execute(pstmt, param_array) )
|
1364
1450
|
error_msg = IBM_DB.getErrormsg(pstmt, IBM_DB::DB_STMT)
|
1365
|
-
|
1366
|
-
error_msg = "Statement execution failed: " + error_msg
|
1367
|
-
else
|
1368
|
-
error_msg = "Statement execution failed"
|
1369
|
-
end
|
1451
|
+
puts_log "Error = #{error_msg}"
|
1370
1452
|
IBM_DB.free_stmt(pstmt) if pstmt
|
1371
1453
|
raise StatementInvalid, error_msg
|
1372
1454
|
else
|
@@ -1374,45 +1456,121 @@ module ActiveRecord
|
|
1374
1456
|
end
|
1375
1457
|
end
|
1376
1458
|
|
1459
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
1460
|
+
:desc, :describe
|
1461
|
+
) # :nodoc:
|
1462
|
+
private_constant :READ_QUERY
|
1463
|
+
|
1464
|
+
def write_query?(sql) # :nodoc:
|
1465
|
+
!READ_QUERY.match?(sql)
|
1466
|
+
rescue ArgumentError # Invalid encoding
|
1467
|
+
!READ_QUERY.match?(sql.b)
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
def explain(arel, binds = [])
|
1471
|
+
sql = "EXPLAIN ALL SET QUERYNO = 1 FOR #{to_sql(arel, binds)}"
|
1472
|
+
stmt = execute(sql, "EXPLAIN")
|
1473
|
+
result = select("select * from explain_statement where explain_level = 'P' and queryno = 1", "EXPLAIN")
|
1474
|
+
return result[0]["total_cost"].to_s
|
1475
|
+
# Ensures to free the resources associated with the statement
|
1476
|
+
ensure
|
1477
|
+
IBM_DB.free_stmt(stmt) if stmt
|
1478
|
+
end
|
1479
|
+
|
1377
1480
|
# Executes +sql+ statement in the context of this connection using
|
1378
1481
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
1379
1482
|
# the executed +sql+ statement.
|
1380
|
-
|
1483
|
+
# Here prepare argument is not used, by default this method creates prepared statment and execute.
|
1484
|
+
def exec_query_ret_stmt(sql, name = 'SQL', binds = [], prepare = false)
|
1485
|
+
puts_log "exec_query_ret_stmt #{sql}"
|
1486
|
+
sql = transform_query(sql)
|
1487
|
+
check_if_write_query(sql)
|
1488
|
+
materialize_transactions
|
1489
|
+
mark_transaction_written_if_write(sql)
|
1381
1490
|
begin
|
1382
|
-
|
1383
|
-
|
1491
|
+
puts_log "SQL = #{sql}"
|
1492
|
+
puts_log "Binds = #{binds}"
|
1493
|
+
param_array = type_casted_binds(binds)
|
1494
|
+
puts_log "Param array = #{param_array}"
|
1495
|
+
puts_log "Prepare flag = #{prepare}"
|
1496
|
+
puts_log "#{caller}"
|
1497
|
+
|
1498
|
+
stmt = @servertype.prepare(sql, name)
|
1499
|
+
if prepare
|
1500
|
+
@statements[sql] = stmt
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
puts_log "Statement = #{stmt}"
|
1504
|
+
log(sql, name, binds, param_array) do
|
1505
|
+
if( stmt )
|
1506
|
+
if(execute_prepared_stmt(stmt, param_array))
|
1507
|
+
return stmt
|
1508
|
+
end
|
1509
|
+
else
|
1510
|
+
return false
|
1511
|
+
end
|
1384
1512
|
end
|
1385
|
-
|
1386
|
-
stmt = prepare(sql, name)
|
1387
|
-
|
1388
|
-
if( stmt )
|
1389
|
-
if(execute_prepared_stmt(stmt, param_array))
|
1390
|
-
return stmt
|
1391
|
-
end
|
1392
|
-
else
|
1393
|
-
return false
|
1394
|
-
end
|
1395
1513
|
ensure
|
1396
1514
|
@offset = @limit = nil
|
1397
1515
|
end
|
1398
1516
|
end
|
1399
1517
|
|
1518
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare = false)
|
1519
|
+
select_prepared(sql, name, binds, prepare)
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
def select_prepared(sql, name = nil, binds = [], prepare = true)
|
1523
|
+
puts_log "select_prepared"
|
1524
|
+
puts_log "select_prepared sql before = #{sql}"
|
1525
|
+
puts_log "select_prepared Binds = #{binds}"
|
1526
|
+
stmt = exec_query_ret_stmt(sql, name, binds, prepare)
|
1527
|
+
if !/^select .*/i.match(sql).nil?
|
1528
|
+
cols = IBM_DB.resultCols(stmt)
|
1529
|
+
|
1530
|
+
if( stmt )
|
1531
|
+
results = fetch_data(stmt)
|
1532
|
+
end
|
1533
|
+
|
1534
|
+
puts_log "select_prepared columns = #{cols}"
|
1535
|
+
puts_log "select_prepared sql after = #{sql}"
|
1536
|
+
puts_log "select_prepared result = #{results}"
|
1537
|
+
else
|
1538
|
+
cols = nil
|
1539
|
+
result = nil
|
1540
|
+
end
|
1541
|
+
if(@isAr3)
|
1542
|
+
return results
|
1543
|
+
else
|
1544
|
+
return ActiveRecord::Result.new(cols, results)
|
1545
|
+
end
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
def check_if_write_query(sql) #For rails 7.1 just remove this function as it will be defined in AbstractAdapter class
|
1549
|
+
if preventing_writes? && write_query?(sql)
|
1550
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
1551
|
+
end
|
1552
|
+
end
|
1553
|
+
|
1400
1554
|
# Executes and logs +sql+ commands and
|
1401
1555
|
# returns a +IBM_DB.Statement+ object.
|
1402
1556
|
def execute(sql, name=nil)
|
1403
1557
|
# Logs and execute the sql instructions.
|
1404
1558
|
# The +log+ method is defined in the parent class +AbstractAdapter+
|
1405
|
-
|
1559
|
+
#sql='INSERT INTO ar_internal_metadata (key, value, created_at, updated_at) VALUES ('10', '10', '10', '10')
|
1560
|
+
puts_log "execute"
|
1561
|
+
puts_log "#{sql}"
|
1562
|
+
sql = transform_query(sql)
|
1563
|
+
check_if_write_query(sql)
|
1564
|
+
materialize_transactions
|
1565
|
+
mark_transaction_written_if_write(sql)
|
1406
1566
|
log(sql , name) do
|
1407
1567
|
@servertype.execute(sql, name)
|
1408
1568
|
end
|
1409
1569
|
end
|
1410
1570
|
|
1411
|
-
def exec_insert(sql,name,binds,pk,sequence_name)
|
1412
|
-
end
|
1413
|
-
|
1414
1571
|
# Executes an "UPDATE" SQL statement
|
1415
1572
|
def update_direct(sql, name = nil)
|
1573
|
+
puts_log "update_direct"
|
1416
1574
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1417
1575
|
@sql = []
|
1418
1576
|
@handle_lobs_triggered = false
|
@@ -1433,13 +1591,14 @@ module ActiveRecord
|
|
1433
1591
|
|
1434
1592
|
#Praveen
|
1435
1593
|
def prepared_update(pstmt, param_array = nil )
|
1594
|
+
puts_log "prepared_update"
|
1436
1595
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1437
1596
|
@sql = []
|
1438
1597
|
@sql_parameter_values = []
|
1439
1598
|
@handle_lobs_triggered = false
|
1440
1599
|
end
|
1441
1600
|
|
1442
|
-
|
1601
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1443
1602
|
|
1444
1603
|
begin
|
1445
1604
|
if execute_prepared_stmt(pstmt, param_array)
|
@@ -1461,11 +1620,12 @@ module ActiveRecord
|
|
1461
1620
|
alias_method :prepared_delete, :prepared_update
|
1462
1621
|
|
1463
1622
|
def update(arel, name = nil, binds = [])
|
1623
|
+
puts_log "update"
|
1464
1624
|
if(@arelVersion < 6 )
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1625
|
+
sql = to_sql(arel)
|
1626
|
+
else
|
1627
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
1628
|
+
end
|
1469
1629
|
|
1470
1630
|
# Make sure the WHERE clause handles NULL's correctly
|
1471
1631
|
sqlarray = sql.split(/\s*WHERE\s*/)
|
@@ -1482,13 +1642,13 @@ module ActiveRecord
|
|
1482
1642
|
sql = sql + sqlarray[size-1]
|
1483
1643
|
end
|
1484
1644
|
|
1485
|
-
|
1645
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1486
1646
|
|
1487
1647
|
if binds.nil? || binds.empty?
|
1488
1648
|
update_direct(sql, name)
|
1489
1649
|
else
|
1490
1650
|
begin
|
1491
|
-
if stmt =
|
1651
|
+
if stmt = exec_query_ret_stmt(sql, name, binds, prepare = true)
|
1492
1652
|
IBM_DB.num_rows(stmt)
|
1493
1653
|
end
|
1494
1654
|
ensure
|
@@ -1501,14 +1661,18 @@ module ActiveRecord
|
|
1501
1661
|
|
1502
1662
|
# Begins the transaction (and turns off auto-committing)
|
1503
1663
|
def begin_db_transaction
|
1664
|
+
puts_log "begin_db_transaction"
|
1665
|
+
log("begin transaction", "TRANSACTION") {
|
1504
1666
|
# Turns off the auto-commit
|
1505
|
-
IBM_DB.autocommit(@connection, IBM_DB::SQL_AUTOCOMMIT_OFF)
|
1667
|
+
IBM_DB.autocommit(@connection, IBM_DB::SQL_AUTOCOMMIT_OFF) }
|
1506
1668
|
end
|
1507
1669
|
|
1508
1670
|
# Commits the transaction and turns on auto-committing
|
1509
1671
|
def commit_db_transaction
|
1672
|
+
puts_log "commit_db_transaction"
|
1673
|
+
log("commit transaction", "TRANSACTION") {
|
1510
1674
|
# Commits the transaction
|
1511
|
-
IBM_DB.commit @connection rescue nil
|
1675
|
+
IBM_DB.commit @connection rescue nil }
|
1512
1676
|
# Turns on auto-committing
|
1513
1677
|
IBM_DB.autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
|
1514
1678
|
end
|
@@ -1516,85 +1680,26 @@ module ActiveRecord
|
|
1516
1680
|
# Rolls back the transaction and turns on auto-committing. Must be
|
1517
1681
|
# done if the transaction block raises an exception or returns false
|
1518
1682
|
def rollback_db_transaction
|
1683
|
+
puts_log "rollback_db_transaction"
|
1684
|
+
log("rollback transaction", "TRANSACTION") {
|
1519
1685
|
# ROLLBACK the transaction
|
1520
|
-
IBM_DB.rollback(@connection) rescue nil
|
1686
|
+
IBM_DB.rollback(@connection) rescue nil }
|
1687
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1521
1688
|
# Turns on auto-committing
|
1522
1689
|
IBM_DB.autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
|
1523
1690
|
end
|
1524
1691
|
|
1525
|
-
def get_limit_offset_clauses(limit,offset)
|
1526
|
-
|
1527
|
-
if limit && limit == 0
|
1528
|
-
clauses = @servertype.get_limit_offset_clauses(limit,0)
|
1529
|
-
else
|
1530
|
-
clauses = @servertype.get_limit_offset_clauses(limit, offset)
|
1531
|
-
end
|
1532
|
-
end
|
1533
|
-
|
1534
|
-
# Modifies a sql statement in order to implement a LIMIT and an OFFSET.
|
1535
|
-
# A LIMIT defines the number of rows that should be fetched, while
|
1536
|
-
# an OFFSET defines from what row the records must be fetched.
|
1537
|
-
# IBM data servers implement a LIMIT in SQL statements through:
|
1538
|
-
# FETCH FIRST n ROWS ONLY, where n is the number of rows required.
|
1539
|
-
# The implementation of OFFSET is more elaborate, and requires the usage of
|
1540
|
-
# subqueries and the ROW_NUMBER() command in order to add row numbering
|
1541
|
-
# as an additional column to a copy of the existing table.
|
1542
|
-
# ==== Examples
|
1543
|
-
# add_limit_offset!('SELECT * FROM staff', {:limit => 10})
|
1544
|
-
# generates: "SELECT * FROM staff FETCH FIRST 10 ROWS ONLY"
|
1545
|
-
#
|
1546
|
-
# add_limit_offset!('SELECT * FROM staff', {:limit => 10, :offset => 30})
|
1547
|
-
# generates "SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_rownum
|
1548
|
-
# FROM (SELECT * FROM staff) AS I) AS O WHERE sys_row_num BETWEEN 31 AND 40"
|
1549
|
-
def add_limit_offset!(sql, options)
|
1550
|
-
limit = options[:limit]
|
1551
|
-
offset = options[:offset]
|
1552
|
-
|
1553
|
-
# if the limit is zero
|
1554
|
-
if limit && limit == 0
|
1555
|
-
# Returns a query that will always generate zero records
|
1556
|
-
# (e.g. WHERE sys_row_num BETWEEN 1 and 0)
|
1557
|
-
if( @pstmt_support_on )
|
1558
|
-
sql = @servertype.query_offset_limit!(sql, 0, limit, options)
|
1559
|
-
else
|
1560
|
-
sql = @servertype.query_offset_limit(sql, 0, limit)
|
1561
|
-
end
|
1562
|
-
# If there is a non-zero limit
|
1563
|
-
else
|
1564
|
-
# If an offset is specified builds the query with offset and limit,
|
1565
|
-
# otherwise retrieves only the first +limit+ rows
|
1566
|
-
if( @pstmt_support_on )
|
1567
|
-
sql = @servertype.query_offset_limit!(sql, offset, limit, options)
|
1568
|
-
else
|
1569
|
-
sql = @servertype.query_offset_limit(sql, offset, limit)
|
1570
|
-
end
|
1571
|
-
end
|
1572
|
-
# Returns the sql query in any case
|
1573
|
-
sql
|
1574
|
-
end # method add_limit_offset!
|
1575
|
-
|
1576
1692
|
def default_sequence_name(table, column) # :nodoc:
|
1693
|
+
puts_log "72"
|
1577
1694
|
"#{table}_#{column}_seq"
|
1578
1695
|
end
|
1579
1696
|
|
1580
|
-
|
1581
1697
|
#==============================================
|
1582
1698
|
# QUOTING
|
1583
1699
|
#==============================================
|
1584
1700
|
|
1585
|
-
# Quote date/time values for use in SQL input.
|
1586
|
-
# Includes microseconds, if the value is a Time responding to usec.
|
1587
|
-
=begin
|
1588
|
-
def quoted_date(value) #:nodoc:
|
1589
|
-
if value.respond_to?(:usec)
|
1590
|
-
"#{super}.#{sprintf("%06d", value.usec)}"
|
1591
|
-
else
|
1592
|
-
super
|
1593
|
-
end
|
1594
|
-
end
|
1595
|
-
=end
|
1596
1701
|
def quote_value_for_pstmt(value, column=nil)
|
1597
|
-
|
1702
|
+
puts_log "quote_value_for_pstmt"
|
1598
1703
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
1599
1704
|
|
1600
1705
|
case value
|
@@ -1621,98 +1726,55 @@ module ActiveRecord
|
|
1621
1726
|
end
|
1622
1727
|
end
|
1623
1728
|
end
|
1624
|
-
|
1625
|
-
#
|
1626
|
-
|
1627
|
-
|
1628
|
-
|
1629
|
-
|
1630
|
-
|
1631
|
-
# when Numeric
|
1632
|
-
# # If the column sql_type is text or string, return the quote value
|
1633
|
-
# if (column && ( column.sql_type.to_s =~ /text|char/i ))
|
1634
|
-
# unless caller[0] =~ /insert_fixture/i
|
1635
|
-
# "'#{value}'"
|
1636
|
-
# else
|
1637
|
-
# "#{value}"
|
1638
|
-
# end
|
1639
|
-
# else
|
1640
|
-
# # value is Numeric, column.sql_type is not a string,
|
1641
|
-
# # therefore it converts the number to string without quoting it
|
1642
|
-
# value.to_s
|
1643
|
-
# end
|
1644
|
-
# when String, ActiveSupport::Multibyte::Chars
|
1645
|
-
# if column && column.sql_type.to_s =~ /binary|blob/i && !(column.sql_type.to_s =~ /for bit data/i)
|
1646
|
-
# # If quoting is required for the insert/update of a BLOB
|
1647
|
-
# unless caller[0] =~ /add_column_options/i
|
1648
|
-
# # Invokes a convertion from string to binary
|
1649
|
-
# @servertype.set_binary_value
|
1650
|
-
# else
|
1651
|
-
# # Quoting required for the default value of a column
|
1652
|
-
# @servertype.set_binary_default(value)
|
1653
|
-
# end
|
1654
|
-
# elsif column && column.sql_type.to_s =~ /text|clob/i
|
1655
|
-
# unless caller[0] =~ /add_column_options/i
|
1656
|
-
# @servertype.set_text_default(quote_string(value))
|
1657
|
-
# else
|
1658
|
-
# @servertype.set_text_default(quote_string(value))
|
1659
|
-
# end
|
1660
|
-
# elsif column && column.sql_type.to_s =~ /xml/i
|
1661
|
-
# unless caller[0] =~ /add_column_options/i
|
1662
|
-
# "#{value}"
|
1663
|
-
# else
|
1664
|
-
# "#{value}"
|
1665
|
-
# end
|
1666
|
-
# else
|
1667
|
-
# unless caller[0] =~ /insert_fixture/i
|
1668
|
-
# super(value)
|
1669
|
-
# else
|
1670
|
-
# "#{value}"
|
1671
|
-
# end
|
1672
|
-
# end
|
1673
|
-
# #when TrueClass then quoted_true # return '1' for true
|
1674
|
-
# when TrueClass
|
1675
|
-
# quoted_true
|
1676
|
-
# #when FalseClass then quoted_false # return '0' for false
|
1677
|
-
# when FalseClass
|
1678
|
-
# quoted_false
|
1679
|
-
# when nil
|
1680
|
-
# "NULL"
|
1681
|
-
# when Date
|
1682
|
-
# "'#{quoted_date(value)}'"
|
1683
|
-
# when Time
|
1684
|
-
# "'#{quoted_date(value)}'"
|
1685
|
-
# when Symbol
|
1686
|
-
# "'#{quote_string(value)}'"
|
1687
|
-
# else
|
1688
|
-
# unless caller[0] =~ /insert_fixture/i
|
1689
|
-
# "'#{quote_string(YAML.dump(value))}'"
|
1690
|
-
# else
|
1691
|
-
# "#{quote_string(YAML.dump(value))}"
|
1692
|
-
# end
|
1693
|
-
# end
|
1694
|
-
# end
|
1695
|
-
# # Quotes a given string, escaping single quote (') characters.
|
1696
|
-
# def quote_string(string)
|
1697
|
-
# #string.gsub(/'/, "''")
|
1698
|
-
# string.gsub('\\', '\&\&').gsub("'", "''")
|
1699
|
-
# end
|
1729
|
+
|
1730
|
+
# Quotes a given string, escaping single quote (') characters.
|
1731
|
+
def quote_string(string)
|
1732
|
+
puts_log "quote_string"
|
1733
|
+
string.gsub(/'/, "''")
|
1734
|
+
#string.gsub('\\', '\&\&').gsub("'", "''")
|
1735
|
+
end
|
1700
1736
|
|
1701
1737
|
# *true* is represented by a smallint 1, *false*
|
1702
1738
|
# by 0, as no native boolean type exists in DB2.
|
1703
1739
|
# Numerics are not quoted in DB2.
|
1704
1740
|
def quoted_true
|
1705
|
-
"
|
1741
|
+
puts_log "quoted_true"
|
1742
|
+
"1".freeze
|
1706
1743
|
end
|
1707
1744
|
|
1708
1745
|
def quoted_false
|
1709
|
-
"
|
1746
|
+
puts_log "quoted_false"
|
1747
|
+
"0".freeze
|
1748
|
+
end
|
1749
|
+
|
1750
|
+
def unquoted_true
|
1751
|
+
puts_log "unquoted_true"
|
1752
|
+
1
|
1753
|
+
end
|
1754
|
+
|
1755
|
+
def unquoted_false
|
1756
|
+
puts_log "unquoted_false"
|
1757
|
+
0
|
1758
|
+
end
|
1759
|
+
|
1760
|
+
def quote_table_name(name)
|
1761
|
+
puts_log "quote_table_name"
|
1762
|
+
if name.start_with?'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
|
1763
|
+
name = "\"#{name}\""
|
1764
|
+
end
|
1765
|
+
name
|
1766
|
+
#@servertype.check_reserved_words(name).gsub('"', '').gsub("'",'')
|
1710
1767
|
end
|
1711
1768
|
|
1712
1769
|
def quote_column_name(name)
|
1713
|
-
|
1770
|
+
puts_log "quote_column_name"
|
1771
|
+
@servertype.check_reserved_words(name).gsub('"', '').gsub("'",'')
|
1714
1772
|
end
|
1715
1773
|
|
1774
|
+
def quoted_binary(value)
|
1775
|
+
puts_log "quoted_binary"
|
1776
|
+
"CAST(x'#{value.hex}' AS BLOB)"
|
1777
|
+
end
|
1716
1778
|
#==============================================
|
1717
1779
|
# SCHEMA STATEMENTS
|
1718
1780
|
#==============================================
|
@@ -1721,7 +1783,7 @@ module ActiveRecord
|
|
1721
1783
|
# database types
|
1722
1784
|
def native_database_types
|
1723
1785
|
{
|
1724
|
-
:primary_key => { :name => @servertype.primary_key_definition(@start_id)},
|
1786
|
+
:primary_key => { :name => @servertype.primary_key_definition(@start_id) },
|
1725
1787
|
:string => { :name => "varchar", :limit => 255 },
|
1726
1788
|
:text => { :name => "clob" },
|
1727
1789
|
:integer => { :name => "integer" },
|
@@ -1750,6 +1812,7 @@ module ActiveRecord
|
|
1750
1812
|
end
|
1751
1813
|
|
1752
1814
|
def build_conn_str_for_dbops()
|
1815
|
+
puts_log "build_conn_str_for_dbops"
|
1753
1816
|
connect_str = "DRIVER={IBM DB2 ODBC DRIVER};ATTACH=true;"
|
1754
1817
|
if(!@host.nil?)
|
1755
1818
|
connect_str << "HOSTNAME=#{@host};"
|
@@ -1761,6 +1824,7 @@ module ActiveRecord
|
|
1761
1824
|
end
|
1762
1825
|
|
1763
1826
|
def drop_database(dbName)
|
1827
|
+
puts_log "drop_database"
|
1764
1828
|
connect_str = build_conn_str_for_dbops()
|
1765
1829
|
|
1766
1830
|
#Ensure connection is closed before trying to drop a database.
|
@@ -1784,6 +1848,7 @@ module ActiveRecord
|
|
1784
1848
|
end
|
1785
1849
|
|
1786
1850
|
def create_database(dbName, codeSet=nil, mode=nil)
|
1851
|
+
puts_log "create_database"
|
1787
1852
|
connect_str = build_conn_str_for_dbops()
|
1788
1853
|
|
1789
1854
|
#Ensure connection is closed before trying to drop a database.
|
@@ -1805,18 +1870,41 @@ module ActiveRecord
|
|
1805
1870
|
raise "Could not create Database due to: #{error}"
|
1806
1871
|
end
|
1807
1872
|
end
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
def valid_type?(type)
|
1813
|
-
#!native_database_types[type].nil?
|
1814
|
-
native_database_types[type].nil?
|
1873
|
+
|
1874
|
+
def valid_type?(type)
|
1875
|
+
!native_database_types[type].nil?
|
1815
1876
|
end
|
1816
|
-
|
1877
|
+
|
1817
1878
|
# IBM data servers do not support limits on certain data types (unlike MySQL)
|
1818
1879
|
# Limit is supported for the {float, decimal, numeric, varchar, clob, blob, graphic, vargraphic} data types.
|
1819
1880
|
def type_to_sql(type, limit=nil, precision=nil, scale=nil )
|
1881
|
+
puts_log "type_to_sql"
|
1882
|
+
puts_log "Type = #{type}, Limit = #{limit}"
|
1883
|
+
|
1884
|
+
if type.to_sym == :binary and limit.class == Hash and limit.has_key?("limit".to_sym)
|
1885
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1886
|
+
sql_segment << "(#{limit[:limit]})"
|
1887
|
+
return sql_segment
|
1888
|
+
end
|
1889
|
+
|
1890
|
+
if type.to_sym == :datetime and limit.class == Hash and limit.has_key?("precision".to_sym)
|
1891
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1892
|
+
if limit[:precision].nil?
|
1893
|
+
return sql_segment
|
1894
|
+
elsif (0..12) === limit[:precision]
|
1895
|
+
sql_segment << "(#{limit[:precision]})"
|
1896
|
+
return sql_segment
|
1897
|
+
else
|
1898
|
+
raise ArgumentError, "No #{sql_segment} type has precision of #{limit[:precision]}. The allowed range of precision is from 0 to 12"
|
1899
|
+
end
|
1900
|
+
end
|
1901
|
+
|
1902
|
+
if type.to_sym == :string and limit.class == Hash and limit.has_key?("limit".to_sym)
|
1903
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1904
|
+
sql_segment << "(#{limit[:limit]})"
|
1905
|
+
return sql_segment
|
1906
|
+
end
|
1907
|
+
|
1820
1908
|
if type.to_sym == :decimal
|
1821
1909
|
if limit.class == Hash
|
1822
1910
|
if limit.has_key?("precision".to_sym)
|
@@ -1834,6 +1922,9 @@ module ActiveRecord
|
|
1834
1922
|
return sql_segment
|
1835
1923
|
elsif scale.nil? && !precision.nil?
|
1836
1924
|
sql_segment << "(#{precision})"
|
1925
|
+
return sql_segment
|
1926
|
+
elsif precision.nil? && !scale.nil?
|
1927
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
1837
1928
|
else
|
1838
1929
|
return sql_segment
|
1839
1930
|
end
|
@@ -1845,50 +1936,48 @@ module ActiveRecord
|
|
1845
1936
|
return sql_segment
|
1846
1937
|
end
|
1847
1938
|
|
1848
|
-
|
1849
|
-
|
1850
|
-
|
1851
|
-
|
1852
|
-
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
end
|
1866
|
-
|
1867
|
-
if type.to_sym == :graphic
|
1868
|
-
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1869
|
-
if limit.class == Hash
|
1870
|
-
if limit.has_key?("limit".to_sym)
|
1871
|
-
limit1 = limit[:limit]
|
1872
|
-
sql_segment << "(#{limit1})"
|
1873
|
-
else
|
1874
|
-
return "graphic(1)"
|
1875
|
-
end
|
1876
|
-
else
|
1877
|
-
if limit != nil
|
1878
|
-
sql_segment << "(#{limit})"
|
1879
|
-
else
|
1880
|
-
return "graphic(1)"
|
1881
|
-
end
|
1882
|
-
end
|
1883
|
-
return sql_segment
|
1939
|
+
if type.to_sym == :vargraphic
|
1940
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1941
|
+
if limit.class == Hash
|
1942
|
+
if limit.has_key?("limit".to_sym)
|
1943
|
+
limit1 = limit[:limit]
|
1944
|
+
sql_segment << "(#{limit1})"
|
1945
|
+
else
|
1946
|
+
return "vargraphic(1)"
|
1947
|
+
end
|
1948
|
+
else
|
1949
|
+
if limit != nil
|
1950
|
+
sql_segment << "(#{limit})"
|
1951
|
+
else
|
1952
|
+
return "vargraphic(1)"
|
1953
|
+
end
|
1954
|
+
end
|
1955
|
+
return sql_segment
|
1884
1956
|
end
|
1885
1957
|
|
1886
|
-
|
1958
|
+
if type.to_sym == :graphic
|
1959
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1960
|
+
if limit.class == Hash
|
1961
|
+
if limit.has_key?("limit".to_sym)
|
1962
|
+
limit1 = limit[:limit]
|
1963
|
+
sql_segment << "(#{limit1})"
|
1964
|
+
else
|
1965
|
+
return "graphic(1)"
|
1966
|
+
end
|
1967
|
+
else
|
1968
|
+
if limit != nil
|
1969
|
+
sql_segment << "(#{limit})"
|
1970
|
+
else
|
1971
|
+
return "graphic(1)"
|
1972
|
+
end
|
1973
|
+
end
|
1974
|
+
return sql_segment
|
1975
|
+
end
|
1887
1976
|
|
1888
1977
|
if limit.class == Hash
|
1889
|
-
return super if limit.has_key?("limit".to_sym).nil?
|
1978
|
+
return super(type) if limit.has_key?("limit".to_sym).nil?
|
1890
1979
|
else
|
1891
|
-
return super if limit.nil?
|
1980
|
+
return super(type) if limit.nil?
|
1892
1981
|
end
|
1893
1982
|
|
1894
1983
|
# strip off limits on data types not supporting them
|
@@ -1899,23 +1988,17 @@ module ActiveRecord
|
|
1899
1988
|
else
|
1900
1989
|
return super(type)
|
1901
1990
|
end
|
1902
|
-
|
1903
1991
|
end
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1992
|
+
|
1910
1993
|
# Returns the maximum length a table alias identifier can be.
|
1911
1994
|
# IBM data servers (cross-platform) table limit is 128 characters
|
1912
1995
|
def table_alias_length
|
1913
1996
|
128
|
1914
1997
|
end
|
1915
|
-
|
1916
1998
|
|
1917
1999
|
# Retrieves table's metadata for a specified shema name
|
1918
2000
|
def tables(name = nil)
|
2001
|
+
puts_log "tables"
|
1919
2002
|
# Initializes the tables array
|
1920
2003
|
tables = []
|
1921
2004
|
# Retrieve table's metadata through IBM_DB driver
|
@@ -1954,16 +2037,13 @@ module ActiveRecord
|
|
1954
2037
|
return tables
|
1955
2038
|
end
|
1956
2039
|
|
1957
|
-
###################################
|
1958
|
-
|
1959
|
-
|
1960
2040
|
# Retrieves views's metadata for a specified shema name
|
1961
2041
|
def views
|
2042
|
+
puts_log "views"
|
1962
2043
|
# Initializes the tables array
|
1963
2044
|
tables = []
|
1964
2045
|
# Retrieve view's metadata through IBM_DB driver
|
1965
|
-
stmt = IBM_DB.tables(@connection, nil,
|
1966
|
-
@servertype.set_case(@schema))
|
2046
|
+
stmt = IBM_DB.tables(@connection, nil, @servertype.set_case(@schema))
|
1967
2047
|
if(stmt)
|
1968
2048
|
begin
|
1969
2049
|
# Fetches all the records available
|
@@ -1996,18 +2076,19 @@ module ActiveRecord
|
|
1996
2076
|
# Returns the tables array
|
1997
2077
|
return tables
|
1998
2078
|
end
|
1999
|
-
|
2000
|
-
|
2079
|
+
|
2001
2080
|
# Returns the primary key of the mentioned table
|
2002
2081
|
def primary_key(table_name)
|
2003
|
-
|
2082
|
+
puts_log "primary_key"
|
2083
|
+
pk_name = []
|
2004
2084
|
stmt = IBM_DB.primary_keys( @connection, nil,
|
2005
2085
|
@servertype.set_case(@schema),
|
2006
|
-
@servertype.set_case(table_name))
|
2086
|
+
@servertype.set_case(table_name.to_s))
|
2007
2087
|
if(stmt)
|
2008
2088
|
begin
|
2009
|
-
|
2010
|
-
|
2089
|
+
while ( pk_index_row = IBM_DB.fetch_array(stmt) )
|
2090
|
+
puts_log "Primary_keys = #{pk_index_row}"
|
2091
|
+
pk_name << pk_index_row[3].downcase
|
2011
2092
|
end
|
2012
2093
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
2013
2094
|
error_msg = IBM_DB.getErrormsg( stmt, IBM_DB::DB_STMT )
|
@@ -2029,11 +2110,19 @@ module ActiveRecord
|
|
2029
2110
|
raise StandardError.new('An unexpected error occurred during primary key retrieval')
|
2030
2111
|
end
|
2031
2112
|
end
|
2032
|
-
|
2113
|
+
if pk_name.length() == 1
|
2114
|
+
return pk_name[0]
|
2115
|
+
elsif pk_name.empty?
|
2116
|
+
return nil
|
2117
|
+
else
|
2118
|
+
return pk_name
|
2119
|
+
end
|
2033
2120
|
end
|
2034
2121
|
|
2035
2122
|
# Returns an array of non-primary key indexes for a specified table name
|
2036
2123
|
def indexes(table_name, name = nil)
|
2124
|
+
puts_log "indexes"
|
2125
|
+
puts_log "Table = #{table_name}"
|
2037
2126
|
# to_s required because +table_name+ may be a symbol.
|
2038
2127
|
table_name = table_name.to_s
|
2039
2128
|
# Checks if a blank table name has been given.
|
@@ -2055,11 +2144,13 @@ module ActiveRecord
|
|
2055
2144
|
if(stmt)
|
2056
2145
|
begin
|
2057
2146
|
while ( pk_index_row = IBM_DB.fetch_array(stmt) )
|
2147
|
+
puts_log "Primary keys = #{pk_index_row}"
|
2148
|
+
puts_log "pk_index = #{pk_index}"
|
2058
2149
|
if pk_index_row[5]
|
2059
2150
|
pk_index_name = pk_index_row[5].downcase
|
2060
2151
|
pk_index_columns = [pk_index_row[3].downcase] # COLUMN_NAME
|
2061
2152
|
if pk_index
|
2062
|
-
pk_index.columns
|
2153
|
+
pk_index.columns << pk_index_columns
|
2063
2154
|
else
|
2064
2155
|
pk_index = IndexDefinition.new(table_name, pk_index_name, true, pk_index_columns)
|
2065
2156
|
end
|
@@ -2115,7 +2206,10 @@ module ActiveRecord
|
|
2115
2206
|
end
|
2116
2207
|
|
2117
2208
|
unless is_composite
|
2118
|
-
indexes
|
2209
|
+
sql = "select remarks from syscat.indexes where tabname = #{quote(table_name.upcase)} and indname = #{quote(index_stats[5])}"
|
2210
|
+
comment = single_value_from_rows(select_prepared(sql).rows)
|
2211
|
+
|
2212
|
+
indexes << IndexDefinition.new(table_name, index_name, index_unique, index_columns, comment: comment)
|
2119
2213
|
index_schema << index_qualifier
|
2120
2214
|
end
|
2121
2215
|
end
|
@@ -2143,6 +2237,7 @@ module ActiveRecord
|
|
2143
2237
|
|
2144
2238
|
# remove the primary key index entry.... should not be dumped by the dumper
|
2145
2239
|
|
2240
|
+
puts_log "Indexes 1 = #{pk_index}"
|
2146
2241
|
i = 0
|
2147
2242
|
indexes.each do |index|
|
2148
2243
|
if pk_index && index.columns == pk_index.columns
|
@@ -2151,12 +2246,13 @@ module ActiveRecord
|
|
2151
2246
|
i = i+1
|
2152
2247
|
end
|
2153
2248
|
# Returns the indexes array
|
2249
|
+
puts_log "Indexes 2 = #{indexes}"
|
2154
2250
|
return indexes
|
2155
2251
|
end
|
2156
2252
|
|
2157
|
-
|
2158
2253
|
# Mapping IBM data servers SQL datatypes to Ruby data types
|
2159
2254
|
def simplified_type2(field_type)
|
2255
|
+
puts_log "simplified_type2"
|
2160
2256
|
case field_type
|
2161
2257
|
# if +field_type+ contains 'for bit data' handle it as a binary
|
2162
2258
|
when /for bit data/i
|
@@ -2193,10 +2289,10 @@ module ActiveRecord
|
|
2193
2289
|
"rowid"
|
2194
2290
|
end
|
2195
2291
|
end # method simplified_type
|
2196
|
-
|
2197
|
-
|
2292
|
+
|
2198
2293
|
# Mapping IBM data servers SQL datatypes to Ruby data types
|
2199
2294
|
def simplified_type(field_type)
|
2295
|
+
puts_log "simplified_type"
|
2200
2296
|
case field_type
|
2201
2297
|
# if +field_type+ contains 'for bit data' handle it as a binary
|
2202
2298
|
when /for bit data/i
|
@@ -2210,7 +2306,7 @@ module ActiveRecord
|
|
2210
2306
|
when /float|double|real/i
|
2211
2307
|
:float
|
2212
2308
|
when /timestamp|datetime/i
|
2213
|
-
:
|
2309
|
+
:datetime
|
2214
2310
|
when /time/i
|
2215
2311
|
:time
|
2216
2312
|
when /date/i
|
@@ -2233,11 +2329,35 @@ module ActiveRecord
|
|
2233
2329
|
:rowid
|
2234
2330
|
end
|
2235
2331
|
end # method simplified_type
|
2236
|
-
|
2237
|
-
|
2332
|
+
|
2333
|
+
def extract_value_from_default(default)
|
2334
|
+
case default
|
2335
|
+
when /IDENTITY GENERATED BY DEFAULT/i
|
2336
|
+
nil
|
2337
|
+
when /^null$/i
|
2338
|
+
nil
|
2339
|
+
# Quoted types
|
2340
|
+
when /^'(.*)'$/m
|
2341
|
+
$1.gsub("''", "'")
|
2342
|
+
# Quoted types
|
2343
|
+
when /^"(.*)"$/m
|
2344
|
+
$1.gsub('""', '"')
|
2345
|
+
# Numeric types
|
2346
|
+
when /\A-?\d+(\.\d*)?\z/
|
2347
|
+
$&
|
2348
|
+
else
|
2349
|
+
# Anything else is blank or some function
|
2350
|
+
# and we can't know the value of that, so return nil.
|
2351
|
+
nil
|
2352
|
+
end
|
2353
|
+
end
|
2354
|
+
|
2238
2355
|
# Returns an array of Column objects for the table specified by +table_name+
|
2239
|
-
def columns(table_name)
|
2356
|
+
def columns(table_name)
|
2357
|
+
default_blob_length = 1048576
|
2240
2358
|
# to_s required because it may be a symbol.
|
2359
|
+
puts_log "columns"
|
2360
|
+
puts_log caller
|
2241
2361
|
table_name = @servertype.set_case(table_name.to_s)
|
2242
2362
|
|
2243
2363
|
# Checks if a blank table name has been given.
|
@@ -2249,74 +2369,96 @@ module ActiveRecord
|
|
2249
2369
|
stmt = IBM_DB.columns( @connection, nil,
|
2250
2370
|
@servertype.set_case(@schema),
|
2251
2371
|
@servertype.set_case(table_name) )
|
2372
|
+
# sql = "select * from sysibm.sqlcolumns where table_name = #{quote(table_name.upcase)}"
|
2373
|
+
if @debug == true
|
2374
|
+
sql = "select * from syscat.columns where tabname = #{quote(table_name.upcase)}"
|
2375
|
+
puts_log "SYSIBM.SQLCOLUMNS = #{select_prepared(sql).rows}"
|
2376
|
+
end
|
2377
|
+
|
2252
2378
|
if(stmt)
|
2253
2379
|
begin
|
2254
2380
|
# Fetches all the columns and assigns them to col.
|
2255
2381
|
# +col+ is an hash with keys/value pairs for a column
|
2256
2382
|
while col = IBM_DB.fetch_assoc(stmt)
|
2383
|
+
puts_log col
|
2257
2384
|
column_name = col["column_name"].downcase
|
2258
2385
|
# Assigns the column default value.
|
2259
2386
|
column_default_value = col["column_def"]
|
2260
|
-
|
2261
|
-
column_default_value = nil if (column_default_value && column_default_value.upcase == 'NULL')
|
2262
|
-
# If default value is IDENTITY GENERATED BY DEFAULT (this value is retrieved in case of id columns)
|
2263
|
-
column_default_value = nil if (column_default_value && column_default_value.upcase =~ /IDENTITY GENERATED BY DEFAULT/i)
|
2264
|
-
# Removes single quotes from the default value
|
2265
|
-
column_default_value.gsub!(/^'(.*)'$/, '\1') unless column_default_value.nil?
|
2387
|
+
default_value = extract_value_from_default(column_default_value)
|
2266
2388
|
# Assigns the column type
|
2267
2389
|
column_type = col["type_name"].downcase
|
2390
|
+
|
2268
2391
|
# Assigns the field length (size) for the column
|
2269
2392
|
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2393
|
+
if column_type =~ /integer|bigint/i
|
2394
|
+
column_length = col["buffer_length"]
|
2395
|
+
else
|
2396
|
+
column_length = col["column_size"]
|
2397
|
+
end
|
2273
2398
|
column_scale = col["decimal_digits"]
|
2274
2399
|
# The initializer of the class Column, requires the +column_length+ to be declared
|
2275
2400
|
# between brackets after the datatype(e.g VARCHAR(50)) for :string and :text types.
|
2276
2401
|
# If it's a "for bit data" field it does a subsitution in place, if not
|
2277
2402
|
# it appends the (column_length) string on the supported data types
|
2278
|
-
|
2279
|
-
|
2280
|
-
column_type.sub!(/ \(\) for bit data/i,"(#{column_length}) FOR BIT DATA") ||
|
2281
|
-
!column_type =~ /char|lob|graphic/i
|
2282
|
-
if column_type =~ /decimal/i
|
2403
|
+
if column_type.match(/decimal|numeric/)
|
2404
|
+
if column_length > 0 and column_scale > 0
|
2283
2405
|
column_type << "(#{column_length},#{column_scale})"
|
2284
|
-
elsif
|
2285
|
-
column_type << "" # override native limits incompatible with table create
|
2286
|
-
else
|
2406
|
+
elsif column_length > 0 and column_scale == 0
|
2287
2407
|
column_type << "(#{column_length})"
|
2288
2408
|
end
|
2409
|
+
elsif column_type.match(/timestamp/)
|
2410
|
+
column_type << "(#{column_scale})"
|
2411
|
+
elsif column_type.match(/varchar/) and column_length > 0
|
2412
|
+
column_type << "(#{column_length})"
|
2289
2413
|
end
|
2290
|
-
|
2414
|
+
|
2291
2415
|
column_nullable = (col["nullable"] == 1) ? true : false
|
2292
2416
|
# Make sure the hidden column (db2_generated_rowid_for_lobs) in DB2 z/OS isn't added to the list
|
2293
|
-
if !(column_name
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
#cast_type = lookup_cast_type(column_type)
|
2299
|
-
|
2300
|
-
ruby_type = simplified_type2(column_type)
|
2417
|
+
if !(column_name.match(/db2_generated_rowid_for_lobs/i))
|
2418
|
+
puts_log "Column type = #{column_type}"
|
2419
|
+
ruby_type = simplified_type(column_type)
|
2420
|
+
puts_log "Ruby type after = #{ruby_type}"
|
2301
2421
|
precision = extract_precision(ruby_type)
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2305
|
-
|
2422
|
+
|
2423
|
+
if column_type.match(/timestamp|integer|bigint|date|time|blob/i)
|
2424
|
+
if column_type.match(/timestamp/i)
|
2425
|
+
precision = column_scale
|
2426
|
+
if !default_value.nil?
|
2427
|
+
default_value[10] = " "
|
2428
|
+
default_value[13] = ":"
|
2429
|
+
default_value[16] = ":"
|
2430
|
+
end
|
2431
|
+
elsif column_type.match(/time/i)
|
2432
|
+
if !default_value.nil?
|
2433
|
+
default_value[2] = ":"
|
2434
|
+
default_value[5] = ":"
|
2435
|
+
end
|
2436
|
+
end
|
2437
|
+
column_scale = nil
|
2438
|
+
if !(column_type.match(/blob/i) and column_length != default_blob_length) and !column_type.match(/bigint/i)
|
2439
|
+
column_length = nil
|
2440
|
+
end
|
2441
|
+
elsif column_type.match(/decimal|numeric/)
|
2442
|
+
precision = column_length
|
2443
|
+
column_length = nil
|
2444
|
+
end
|
2445
|
+
|
2446
|
+
if ruby_type.to_s == "boolean"
|
2447
|
+
column_type = "boolean"
|
2448
|
+
end
|
2449
|
+
|
2450
|
+
default_function = extract_default_function(default_value, column_default_value)
|
2451
|
+
|
2306
2452
|
sqltype_metadata = SqlTypeMetadata.new(
|
2307
2453
|
#sql_type: sql_type,
|
2308
|
-
sql_type:
|
2454
|
+
sql_type: column_type,
|
2309
2455
|
type: ruby_type,
|
2310
2456
|
limit: column_length,
|
2311
2457
|
precision: precision,
|
2312
2458
|
scale: column_scale,
|
2313
2459
|
)
|
2314
2460
|
|
2315
|
-
columns << Column.new(column_name,
|
2316
|
-
|
2317
|
-
#else
|
2318
|
-
# columns << IBM_DBColumn.new(column_name, column_default_value, column_type, column_nullable)
|
2319
|
-
#end
|
2461
|
+
columns << Column.new(column_name, default_value, sqltype_metadata, column_nullable, default_function, comment: col["remarks"])
|
2320
2462
|
end
|
2321
2463
|
end
|
2322
2464
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
@@ -2326,7 +2468,7 @@ module ActiveRecord
|
|
2326
2468
|
else
|
2327
2469
|
error_msg = "An unexpected error occurred during retrieval of column metadata"
|
2328
2470
|
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
2329
|
-
|
2471
|
+
# raise error_msg
|
2330
2472
|
end
|
2331
2473
|
ensure # Free resources associated with the statement
|
2332
2474
|
IBM_DB.free_stmt(stmt) if stmt
|
@@ -2340,10 +2482,24 @@ module ActiveRecord
|
|
2340
2482
|
end
|
2341
2483
|
end
|
2342
2484
|
# Returns the columns array
|
2485
|
+
puts_log "Inside def columns() #{columns}"
|
2343
2486
|
return columns
|
2344
2487
|
end
|
2345
|
-
|
2488
|
+
|
2489
|
+
def extract_precision(sql_type)
|
2490
|
+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
2491
|
+
end
|
2492
|
+
|
2493
|
+
def extract_default_function(default_value, default)
|
2494
|
+
default if has_default_function?(default_value, default)
|
2495
|
+
end
|
2496
|
+
|
2497
|
+
def has_default_function?(default_value, default)
|
2498
|
+
!default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
2499
|
+
end
|
2500
|
+
|
2346
2501
|
def foreign_keys(table_name)
|
2502
|
+
puts_log "foreign_keys #{table_name}"
|
2347
2503
|
#fetch the foreign keys of the table using function foreign_keys
|
2348
2504
|
#PKTABLE_NAME:: fk_row[2] Name of the table containing the primary key.
|
2349
2505
|
#PKCOLUMN_NAME:: fk_row[3] Name of the column containing the primary key.
|
@@ -2359,15 +2515,16 @@ module ActiveRecord
|
|
2359
2515
|
|
2360
2516
|
if(stmt)
|
2361
2517
|
begin
|
2362
|
-
while ( fk_row = IBM_DB.fetch_array(stmt) )
|
2518
|
+
while ( fk_row = IBM_DB.fetch_array(stmt) )
|
2519
|
+
puts_log "foreign_keys fetch = #{fk_row}"
|
2363
2520
|
options = {
|
2364
|
-
column: fk_row[7],
|
2365
|
-
name: fk_row[11],
|
2366
|
-
primary_key: fk_row[3],
|
2521
|
+
column: fk_row[7].downcase,
|
2522
|
+
name: fk_row[11].downcase,
|
2523
|
+
primary_key: fk_row[3].downcase,
|
2367
2524
|
}
|
2368
2525
|
options[:on_update] = extract_foreign_key_action(fk_row[9])
|
2369
2526
|
options[:on_delete] = extract_foreign_key_action(fk_row[10])
|
2370
|
-
foreignKeys << ForeignKeyDefinition.new(fk_row[6],
|
2527
|
+
foreignKeys << ForeignKeyDefinition.new(fk_row[6].downcase, fk_row[2].downcase, options)
|
2371
2528
|
end
|
2372
2529
|
|
2373
2530
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
@@ -2377,7 +2534,7 @@ module ActiveRecord
|
|
2377
2534
|
else
|
2378
2535
|
error_msg = "An unexpected error occurred during retrieval of foreign key metadata"
|
2379
2536
|
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
2380
|
-
|
2537
|
+
# raise error_msg
|
2381
2538
|
end
|
2382
2539
|
ensure # Free resources associated with the statement
|
2383
2540
|
IBM_DB.free_stmt(stmt) if stmt
|
@@ -2390,24 +2547,25 @@ module ActiveRecord
|
|
2390
2547
|
raise StandardError.new('An unexpected error occurred during foreign key retrieval')
|
2391
2548
|
end
|
2392
2549
|
end
|
2393
|
-
|
2394
|
-
|
2395
|
-
|
2550
|
+
#Returns the foreignKeys array
|
2551
|
+
return foreignKeys
|
2552
|
+
end
|
2396
2553
|
|
2397
|
-
|
2398
|
-
|
2399
|
-
|
2400
|
-
|
2401
|
-
|
2402
|
-
|
2403
|
-
|
2554
|
+
def extract_foreign_key_action(specifier) # :nodoc:
|
2555
|
+
puts_log "extract_foreign_key_action"
|
2556
|
+
case specifier
|
2557
|
+
when 0; :cascade
|
2558
|
+
when 1; :restrict
|
2559
|
+
when 2; :nullify
|
2560
|
+
end
|
2404
2561
|
end
|
2405
2562
|
|
2406
2563
|
def supports_disable_referential_integrity? #:nodoc:
|
2407
|
-
|
2408
|
-
|
2564
|
+
true
|
2565
|
+
end
|
2409
2566
|
|
2410
|
-
|
2567
|
+
def disable_referential_integrity #:nodoc:
|
2568
|
+
puts_log "disable_referential_integrity"
|
2411
2569
|
if supports_disable_referential_integrity?
|
2412
2570
|
alter_foreign_keys(tables, true)
|
2413
2571
|
end
|
@@ -2416,43 +2574,303 @@ module ActiveRecord
|
|
2416
2574
|
ensure
|
2417
2575
|
if supports_disable_referential_integrity?
|
2418
2576
|
alter_foreign_keys(tables, false)
|
2419
|
-
end
|
2420
|
-
|
2421
|
-
end
|
2577
|
+
end
|
2578
|
+
end
|
2422
2579
|
|
2423
2580
|
def alter_foreign_keys(tables, not_enforced)
|
2581
|
+
puts_log "alter_foreign_keys"
|
2424
2582
|
enforced = not_enforced ? 'NOT ENFORCED' : 'ENFORCED'
|
2425
2583
|
tables.each do |table|
|
2426
2584
|
foreign_keys(table).each do |fk|
|
2427
|
-
execute("ALTER TABLE #{@servertype.set_case(fk.from_table)} ALTER FOREIGN KEY #{@servertype.set_case(fk.name)} #{enforced}")
|
2585
|
+
execute("ALTER TABLE #{@servertype.set_case(fk.from_table)} ALTER FOREIGN KEY #{@servertype.set_case(fk.name)} #{enforced}")
|
2586
|
+
end
|
2587
|
+
end
|
2588
|
+
end
|
2589
|
+
|
2590
|
+
def primary_keys(table_name) # :nodoc:
|
2591
|
+
puts_log "primary_keys"
|
2592
|
+
raise ArgumentError unless table_name.present?
|
2593
|
+
primary_key(table_name)
|
2594
|
+
end
|
2595
|
+
|
2596
|
+
# Adds comment for given table column or drops it if +comment+ is a +nil+
|
2597
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
2598
|
+
puts_log "change_column_comment"
|
2599
|
+
clear_cache!
|
2600
|
+
comment = extract_new_comment_value(comment_or_changes)
|
2601
|
+
if comment.nil?
|
2602
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS ''"
|
2603
|
+
else
|
2604
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
|
2605
|
+
end
|
2606
|
+
end
|
2607
|
+
|
2608
|
+
# Adds comment for given table or drops it if +comment+ is a +nil+
|
2609
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
2610
|
+
puts_log "change_table_comment"
|
2611
|
+
clear_cache!
|
2612
|
+
comment = extract_new_comment_value(comment_or_changes)
|
2613
|
+
if comment.nil?
|
2614
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS ''"
|
2615
|
+
else
|
2616
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
|
2617
|
+
end
|
2618
|
+
end
|
2619
|
+
|
2620
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
2621
|
+
puts_log "add_column"
|
2622
|
+
clear_cache!
|
2623
|
+
puts_log "add_column info #{table_name}, #{column_name}, #{type}, #{options}"
|
2624
|
+
puts_log caller
|
2625
|
+
if (!type.nil? && type.to_s == "primary_key") or (options.key?(:primary_key) and options[:primary_key] == true)
|
2626
|
+
if !type.nil? and type.to_s != "primary_key"
|
2627
|
+
execute "ALTER TABLE #{table_name} ADD COLUMN #{column_name} #{type} NOT NULL DEFAULT 0"
|
2628
|
+
else
|
2629
|
+
execute "ALTER TABLE #{table_name} ADD COLUMN #{column_name} INTEGER NOT NULL DEFAULT 0"
|
2428
2630
|
end
|
2631
|
+
execute "ALTER TABLE #{table_name} alter column #{column_name} drop default"
|
2632
|
+
execute "ALTER TABLE #{table_name} alter column #{column_name} set GENERATED BY DEFAULT AS IDENTITY (START WITH 1000)"
|
2633
|
+
execute "ALTER TABLE #{table_name} add primary key (#{column_name})"
|
2634
|
+
else
|
2635
|
+
super
|
2429
2636
|
end
|
2637
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
2638
|
+
end
|
2639
|
+
|
2640
|
+
def table_comment(table_name) # :nodoc:
|
2641
|
+
puts_log "table_comment"
|
2642
|
+
sql = "select remarks from syscat.tables where tabname = #{quote(table_name.upcase)}"
|
2643
|
+
single_value_from_rows(select_prepared(sql).rows)
|
2644
|
+
end
|
2645
|
+
|
2646
|
+
def add_index(table_name, column_name, **options) #:nodoc:
|
2647
|
+
puts_log "add_index"
|
2648
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
2649
|
+
|
2650
|
+
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
2651
|
+
if_not_exists = false if if_not_exists
|
2652
|
+
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
2653
|
+
result = execute schema_creation.accept(create_index)
|
2654
|
+
|
2655
|
+
execute "COMMENT ON INDEX #{quote_column_name(index.name)} IS #{quote(index.comment)}" if index.comment
|
2656
|
+
result
|
2657
|
+
end
|
2658
|
+
|
2659
|
+
def query_values(sql, name = nil) # :nodoc:
|
2660
|
+
puts_log "query_values"
|
2661
|
+
select_prepared(sql).rows.map(&:first)
|
2662
|
+
end
|
2663
|
+
|
2664
|
+
def data_source_sql(name = nil, type: nil)
|
2665
|
+
puts_log "data_source_sql"
|
2666
|
+
sql = +"SELECT tabname FROM (SELECT tabname, type FROM syscat.tables "
|
2667
|
+
sql << " WHERE tabschema = #{quote(@schema.upcase)}) subquery"
|
2668
|
+
if type || name
|
2669
|
+
conditions = []
|
2670
|
+
conditions << "subquery.type = #{quote(type.upcase)}" if type
|
2671
|
+
conditions << "subquery.tabname = #{quote(name.upcase)}" if name
|
2672
|
+
sql << " WHERE #{conditions.join(" AND ")}"
|
2673
|
+
end
|
2674
|
+
sql
|
2430
2675
|
end
|
2431
2676
|
|
2677
|
+
# Returns an array of table names defined in the database.
|
2678
|
+
def tables
|
2679
|
+
puts_log "tables"
|
2680
|
+
query_values(data_source_sql(type: "T"), "SCHEMA").map(&:downcase)
|
2681
|
+
end
|
2682
|
+
|
2683
|
+
# Checks to see if the table +table_name+ exists on the database.
|
2684
|
+
#
|
2685
|
+
# table_exists?(:developers)
|
2686
|
+
#
|
2687
|
+
def table_exists?(table_name)
|
2688
|
+
puts_log "table_exists? = #{table_name}"
|
2689
|
+
query_values(data_source_sql(table_name, type: "T"), "SCHEMA").any? if table_name.present?
|
2690
|
+
rescue NotImplementedError
|
2691
|
+
tables.include?(table_name.to_s)
|
2692
|
+
end
|
2693
|
+
|
2694
|
+
# Returns an array of view names defined in the database.
|
2695
|
+
def views
|
2696
|
+
puts_log "views"
|
2697
|
+
query_values(data_source_sql(type: "V"), "SCHEMA").map(&:downcase)
|
2698
|
+
end
|
2699
|
+
|
2700
|
+
# Checks to see if the view +view_name+ exists on the database.
|
2701
|
+
#
|
2702
|
+
# view_exists?(:ebooks)
|
2703
|
+
#
|
2704
|
+
def view_exists?(view_name)
|
2705
|
+
puts_log "view_exists?"
|
2706
|
+
query_values(data_source_sql(view_name, type: "V"), "SCHEMA").any? if view_name.present?
|
2707
|
+
rescue NotImplementedError
|
2708
|
+
views.include?(view_name.to_s)
|
2709
|
+
end
|
2710
|
+
|
2711
|
+
# Returns the relation names useable to back Active Record models.
|
2712
|
+
# For most adapters this means all #tables and #views.
|
2713
|
+
def data_sources
|
2714
|
+
puts_log "data_sources"
|
2715
|
+
query_values(data_source_sql, "SCHEMA").map(&:downcase)
|
2716
|
+
rescue NotImplementedError
|
2717
|
+
tables | views
|
2718
|
+
end
|
2719
|
+
|
2720
|
+
def create_schema_dumper(options)
|
2721
|
+
puts_log "create_schema_dumper"
|
2722
|
+
SchemaDumper.create(self, options)
|
2723
|
+
end
|
2724
|
+
|
2725
|
+
def table_options(table_name) # :nodoc:
|
2726
|
+
puts_log "table_options"
|
2727
|
+
if comment = table_comment(table_name)
|
2728
|
+
{ comment: comment }
|
2729
|
+
end
|
2730
|
+
end
|
2731
|
+
|
2732
|
+
def remove_columns(table_name, *column_names, type: nil, **options)
|
2733
|
+
if column_names.empty?
|
2734
|
+
raise ArgumentError.new("You must specify at least one column name. Example: remove_columns(:people, :first_name)")
|
2735
|
+
end
|
2736
|
+
|
2737
|
+
remove_column_fragments = remove_columns_for_alter(table_name, *column_names, type: type, **options)
|
2738
|
+
execute "ALTER TABLE #{quote_table_name(table_name)} #{remove_column_fragments.join(' ')}"
|
2739
|
+
end
|
2740
|
+
|
2432
2741
|
# Renames a table.
|
2433
2742
|
# ==== Example
|
2434
2743
|
# rename_table('octopuses', 'octopi')
|
2435
2744
|
# Overriden to satisfy IBM data servers syntax
|
2436
2745
|
def rename_table(name, new_name)
|
2746
|
+
puts_log "rename_table"
|
2747
|
+
name = quote_column_name(name)
|
2748
|
+
new_name = quote_column_name(new_name)
|
2749
|
+
puts_log "90 old_table = #{name}, new_table = #{new_name}"
|
2437
2750
|
# SQL rename table statement
|
2751
|
+
index_list = indexes(name)
|
2752
|
+
puts_log "Index List = #{index_list}"
|
2753
|
+
drop_table_indexes(index_list)
|
2438
2754
|
rename_table_sql = "RENAME TABLE #{name} TO #{new_name}"
|
2439
2755
|
stmt = execute(rename_table_sql)
|
2756
|
+
create_table_indexes(index_list, new_name)
|
2440
2757
|
# Ensures to free the resources associated with the statement
|
2441
2758
|
ensure
|
2442
2759
|
IBM_DB.free_stmt(stmt) if stmt
|
2443
2760
|
end
|
2444
2761
|
|
2445
|
-
|
2446
|
-
|
2447
|
-
|
2448
|
-
|
2449
|
-
|
2762
|
+
def drop_table_indexes(index_list)
|
2763
|
+
puts_log "drop_table_indexes"
|
2764
|
+
index_list.each do |indexs|
|
2765
|
+
remove_index(indexs.table, name: indexs.name)
|
2766
|
+
end
|
2767
|
+
end
|
2768
|
+
|
2769
|
+
def create_table_indexes(index_list, new_table)
|
2770
|
+
puts_log "create_table_indexes"
|
2771
|
+
index_list.each do |indexs|
|
2772
|
+
generated_index_name = index_name(indexs.table, column: indexs.columns)
|
2773
|
+
custom_index_name = indexs.name
|
2774
|
+
|
2775
|
+
if generated_index_name == custom_index_name
|
2776
|
+
add_index(new_table, indexs.columns, unique: indexs.unique)
|
2777
|
+
else
|
2778
|
+
add_index(new_table, indexs.columns, name: custom_index_name, unique: indexs.unique)
|
2779
|
+
end
|
2780
|
+
end
|
2781
|
+
end
|
2782
|
+
|
2783
|
+
def drop_column_indexes(index_list, column_name)
|
2784
|
+
puts_log "drop_column_indexes"
|
2785
|
+
index_list.each do |indexs|
|
2786
|
+
if indexs.columns.class == Array
|
2787
|
+
next if !indexs.columns.include?(column_name)
|
2788
|
+
else
|
2789
|
+
next if indexs.columns != column_name
|
2790
|
+
end
|
2791
|
+
remove_index(indexs.table, name: indexs.name)
|
2792
|
+
end
|
2793
|
+
end
|
2794
|
+
|
2795
|
+
def create_column_indexes(index_list, column_name, new_column_name)
|
2796
|
+
puts_log "create_column_indexes"
|
2797
|
+
index_list.each do |indexs|
|
2798
|
+
generated_index_name = index_name(indexs.table, column: indexs.columns)
|
2799
|
+
custom_index_name = indexs.name
|
2800
|
+
if indexs.columns.class == Array
|
2801
|
+
next if !indexs.columns.include?(column_name)
|
2802
|
+
indexs.columns[indexs.columns.index(column_name)] = new_column_name
|
2803
|
+
else
|
2804
|
+
next if indexs.columns != column_name
|
2805
|
+
indexs.columns = new_column_name
|
2806
|
+
end
|
2807
|
+
|
2808
|
+
if generated_index_name == custom_index_name
|
2809
|
+
add_index(indexs.table, indexs.columns, unique: indexs.unique)
|
2810
|
+
else
|
2811
|
+
add_index(indexs.table, indexs.columns, name: custom_index_name, unique: indexs.unique)
|
2812
|
+
end
|
2813
|
+
end
|
2814
|
+
end
|
2815
|
+
|
2816
|
+
# Renames a column in a table.
|
2817
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
2818
|
+
puts_log "rename_column"
|
2819
|
+
column_name = quote_column_name(column_name)
|
2820
|
+
new_column_name = quote_column_name(new_column_name)
|
2821
|
+
puts_log "rename_column #{table_name}, #{column_name}, #{new_column_name}"
|
2822
|
+
clear_cache!
|
2823
|
+
index_list = indexes(table_name)
|
2824
|
+
puts_log "Index List = #{index_list}"
|
2825
|
+
fkey_list = foreign_keys(table_name)
|
2826
|
+
puts_log "ForeignKey = #{fkey_list}"
|
2827
|
+
drop_column_indexes(index_list, column_name)
|
2828
|
+
fkey_removed = remove_foreign_key_byColumn(fkey_list, table_name, column_name)
|
2829
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}")
|
2830
|
+
add_foreign_keyList(fkey_list, table_name, column_name, new_column_name) if fkey_removed
|
2831
|
+
create_column_indexes(index_list, column_name, new_column_name)
|
2832
|
+
end
|
2833
|
+
|
2834
|
+
def add_foreign_keyList(fkey_list, table_name, column_name, new_column_name)
|
2835
|
+
puts_log "add_foreign_keyList = #{table_name}, #{column_name}, #{fkey_list}"
|
2836
|
+
fkey_list.each do |fkey|
|
2837
|
+
if fkey.options[:column] == column_name
|
2838
|
+
add_foreign_key(table_name, strip_table_name_prefix_and_suffix(fkey.to_table), column: new_column_name)
|
2839
|
+
end
|
2840
|
+
end
|
2841
|
+
end
|
2842
|
+
|
2843
|
+
def remove_foreign_key_byColumn(fkey_list, table_name, column_name)
|
2844
|
+
puts_log "remove_foreign_key_byColumn = #{table_name}, #{column_name}, #{fkey_list}"
|
2845
|
+
fkey_removed = false
|
2846
|
+
fkey_list.each do |fkey|
|
2847
|
+
if fkey.options[:column] == column_name
|
2848
|
+
remove_foreign_key(table_name, column: column_name)
|
2849
|
+
fkey_removed = true
|
2850
|
+
end
|
2851
|
+
end
|
2852
|
+
fkey_removed
|
2853
|
+
end
|
2854
|
+
|
2855
|
+
def rename_index(table_name, old_name, new_name)
|
2856
|
+
puts_log "rename_index"
|
2857
|
+
old_name = old_name.to_s
|
2858
|
+
new_name = new_name.to_s
|
2859
|
+
validate_index_length!(table_name, new_name)
|
2860
|
+
|
2861
|
+
# this is a naive implementation; some DBs may support this more efficiently (PostgreSQL, for instance)
|
2862
|
+
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
2863
|
+
return unless old_index_def
|
2864
|
+
remove_index(table_name, name: old_name)
|
2865
|
+
add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
|
2450
2866
|
end
|
2451
2867
|
|
2452
2868
|
# Removes the column from the table definition.
|
2453
2869
|
# ===== Examples
|
2454
2870
|
# remove_column(:suppliers, :qualification)
|
2455
|
-
def remove_column(table_name, column_name)
|
2871
|
+
def remove_column(table_name, column_name, type = nil, **options)
|
2872
|
+
puts_log "remove_column"
|
2873
|
+
return if options[:if_exists] == true && !column_exists?(table_name, column_name)
|
2456
2874
|
@servertype.remove_column(table_name, column_name)
|
2457
2875
|
end
|
2458
2876
|
|
@@ -2462,28 +2880,20 @@ module ActiveRecord
|
|
2462
2880
|
# change_column(:suppliers, :name, :string, :limit => 80)
|
2463
2881
|
# change_column(:accounts, :description, :text)
|
2464
2882
|
def change_column(table_name, column_name, type, options = {})
|
2883
|
+
puts_log "change_column"
|
2465
2884
|
@servertype.change_column(table_name, column_name, type, options)
|
2885
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
2466
2886
|
end
|
2467
2887
|
|
2468
2888
|
#Add distinct clause to the sql if there is no order by specified
|
2469
2889
|
def distinct(columns, order_by)
|
2890
|
+
puts_log "distinct"
|
2470
2891
|
if order_by.nil?
|
2471
2892
|
"DISTINCT #{columns}"
|
2472
2893
|
else
|
2473
2894
|
"#{columns}"
|
2474
2895
|
end
|
2475
2896
|
end
|
2476
|
-
|
2477
|
-
def columns_for_distinct(columns, orders) #:nodoc:
|
2478
|
-
order_columns = orders.reject(&:blank?).map{ |s|
|
2479
|
-
# Convert Arel node to string
|
2480
|
-
s = s.to_sql unless s.is_a?(String)
|
2481
|
-
# Remove any ASC/DESC modifiers
|
2482
|
-
s.gsub(/\s+(?:ASC|DESC)\b/i, '')
|
2483
|
-
.gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
|
2484
|
-
}.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
|
2485
|
-
[super, *order_columns].join(', ')
|
2486
|
-
end
|
2487
2897
|
|
2488
2898
|
# Sets a new default value for a column. This does not set the default
|
2489
2899
|
# value to +NULL+, instead, it needs DatabaseStatements#execute which
|
@@ -2493,43 +2903,42 @@ module ActiveRecord
|
|
2493
2903
|
# change_column_default(:accounts, :authorized, 1)
|
2494
2904
|
# Method overriden to satisfy IBM data servers syntax.
|
2495
2905
|
def change_column_default(table_name, column_name, default)
|
2906
|
+
puts_log "change_column_default"
|
2496
2907
|
@servertype.change_column_default(table_name, column_name, default)
|
2497
2908
|
end
|
2498
2909
|
|
2499
2910
|
#Changes the nullability value of a column
|
2500
2911
|
def change_column_null(table_name, column_name, null, default = nil)
|
2912
|
+
puts_log "change_column_null"
|
2501
2913
|
@servertype.change_column_null(table_name, column_name, null, default)
|
2502
2914
|
end
|
2503
2915
|
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
2507
|
-
|
2508
|
-
|
2509
|
-
|
2510
|
-
|
2511
|
-
|
2512
|
-
#
|
2513
|
-
# You can remove an index on multiple columns by specifying the first column.
|
2514
|
-
# add_index :accounts, [:username, :password]
|
2515
|
-
# remove_index :accounts, :username
|
2516
|
-
# Overriden to use the IBM data servers SQL syntax.
|
2517
|
-
def remove_index(table_name, options = {})
|
2518
|
-
execute("DROP INDEX #{index_name(table_name, options)}")
|
2916
|
+
def remove_index(table_name, column_name = nil, **options)
|
2917
|
+
puts_log "remove_index"
|
2918
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
2919
|
+
execute("DROP INDEX #{index_name_for_remove(table_name, column_name, options)}")
|
2920
|
+
end
|
2921
|
+
|
2922
|
+
def column_for(table_name, column_name)
|
2923
|
+
super
|
2519
2924
|
end
|
2520
2925
|
|
2521
2926
|
protected
|
2522
|
-
def initialize_type_map(m) # :nodoc:
|
2927
|
+
def initialize_type_map(m = type_map) # :nodoc:
|
2928
|
+
puts_log "initialize_type_map"
|
2523
2929
|
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
2524
2930
|
register_class_with_limit m, %r(char)i, Type::String
|
2525
2931
|
register_class_with_limit m, %r(binary)i, Type::Binary
|
2526
2932
|
register_class_with_limit m, %r(text)i, Type::Text
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2933
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
2934
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
2935
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
2530
2936
|
register_class_with_limit m, %r(float)i, Type::Float
|
2531
|
-
|
2532
|
-
|
2937
|
+
|
2938
|
+
m.register_type %r(^bigint)i, Type::Integer.new(limit: 8)
|
2939
|
+
m.register_type %r(^int)i, Type::Integer.new(limit: 4)
|
2940
|
+
m.register_type %r(^smallint)i, Type::Integer.new(limit: 2)
|
2941
|
+
m.register_type %r(^tinyint)i, Type::Integer.new(limit: 1)
|
2533
2942
|
|
2534
2943
|
m.alias_type %r(blob)i, 'binary'
|
2535
2944
|
m.alias_type %r(clob)i, 'text'
|
@@ -2552,13 +2961,21 @@ module ActiveRecord
|
|
2552
2961
|
|
2553
2962
|
m.alias_type %r(xml)i, 'text'
|
2554
2963
|
m.alias_type %r(for bit data)i, 'binary'
|
2555
|
-
m.alias_type %r(smallint)i, 'boolean'
|
2556
2964
|
m.alias_type %r(serial)i, 'int'
|
2557
2965
|
m.alias_type %r(decfloat)i, 'decimal'
|
2558
2966
|
m.alias_type %r(real)i, 'decimal'
|
2559
2967
|
m.alias_type %r(graphic)i, 'binary'
|
2560
2968
|
m.alias_type %r(rowid)i, 'int'
|
2561
2969
|
end
|
2970
|
+
|
2971
|
+
class SchemaDumper < ConnectionAdapters::SchemaDumper
|
2972
|
+
def dump(stream) # Like in abstract class, we no need to call header() & trailer().
|
2973
|
+
header(stream)
|
2974
|
+
extensions(stream)
|
2975
|
+
tables(stream)
|
2976
|
+
stream
|
2977
|
+
end
|
2978
|
+
end
|
2562
2979
|
end # class IBM_DBAdapter
|
2563
2980
|
|
2564
2981
|
# This class contains common code across DB's (DB2 LUW, zOS, i5 and IDS)
|
@@ -2581,12 +2998,14 @@ module ActiveRecord
|
|
2581
2998
|
end
|
2582
2999
|
|
2583
3000
|
def check_reserved_words(col_name)
|
3001
|
+
@adapter.puts_log "check_reserved_words"
|
2584
3002
|
col_name.to_s
|
2585
3003
|
end
|
2586
3004
|
|
2587
3005
|
# This is supported by the DB2 for Linux, UNIX, Windows data servers
|
2588
3006
|
# and by the DB2 for i5 data servers
|
2589
3007
|
def remove_column(table_name, column_name)
|
3008
|
+
@adapter.puts_log "remove_column"
|
2590
3009
|
begin
|
2591
3010
|
@adapter.execute "ALTER TABLE #{table_name} DROP #{column_name}"
|
2592
3011
|
reorg_table(table_name)
|
@@ -2603,12 +3022,13 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2603
3022
|
end
|
2604
3023
|
|
2605
3024
|
def select(stmt)
|
3025
|
+
@adapter.puts_log "select"
|
2606
3026
|
results = []
|
2607
3027
|
# Fetches all the results available. IBM_DB.fetch_assoc(stmt) returns
|
2608
3028
|
# an hash for each single record.
|
2609
3029
|
# The loop stops when there aren't any more valid records to fetch
|
2610
3030
|
begin
|
2611
|
-
|
3031
|
+
if(@isAr3)
|
2612
3032
|
while single_hash = IBM_DB.fetch_assoc(stmt)
|
2613
3033
|
# Add the record to the +results+ array
|
2614
3034
|
results << single_hash
|
@@ -2633,6 +3053,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2633
3053
|
end
|
2634
3054
|
|
2635
3055
|
def select_rows(sql, name, stmt, results)
|
3056
|
+
@adapter.puts_log "select_rows"
|
2636
3057
|
# Fetches all the results available. IBM_DB.fetch_array(stmt) returns
|
2637
3058
|
# an array representing a row in a result set.
|
2638
3059
|
# The loop stops when there aren't any more valid records to fetch
|
@@ -2656,6 +3077,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2656
3077
|
|
2657
3078
|
# Praveen
|
2658
3079
|
def prepare(sql,name = nil)
|
3080
|
+
@adapter.puts_log "prepare"
|
2659
3081
|
begin
|
2660
3082
|
stmt = IBM_DB.prepare(@adapter.connection, sql)
|
2661
3083
|
if( stmt )
|
@@ -2667,61 +3089,39 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2667
3089
|
if prep_err && !prep_err.message.empty?
|
2668
3090
|
raise "Failed to prepare sql #{sql} due to: #{prep_err}"
|
2669
3091
|
else
|
2670
|
-
raise
|
3092
|
+
raise "An unexpected error occurred during SQLprepare"
|
2671
3093
|
end
|
2672
3094
|
end
|
2673
3095
|
end
|
2674
3096
|
|
2675
3097
|
# Akhil Tcheck for if_exits added so that it will try to drop even if the table does not exit.
|
2676
3098
|
def execute(sql, name = nil)
|
2677
|
-
|
3099
|
+
@adapter.puts_log "execute #{sql}"
|
3100
|
+
|
2678
3101
|
begin
|
2679
|
-
if
|
3102
|
+
if @adapter.connection == nil || @adapter.connection == false
|
3103
|
+
raise ActiveRecord::ConnectionNotEstablished, "called on a closed database"
|
3104
|
+
elsif stmt = IBM_DB.exec(@adapter.connection, sql)
|
2680
3105
|
stmt # Return the statement object
|
2681
3106
|
else
|
2682
|
-
raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
|
3107
|
+
raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN ), sql
|
2683
3108
|
end
|
2684
3109
|
rescue StandardError => exec_err
|
2685
3110
|
if exec_err && !exec_err.message.empty?
|
2686
|
-
|
3111
|
+
@adapter.puts_log "104 error = #{exec_err.message}"
|
3112
|
+
@adapter.puts_log "104 sql = #{sql}"
|
3113
|
+
raise StatementInvalid
|
2687
3114
|
else
|
2688
3115
|
raise
|
2689
3116
|
end
|
2690
3117
|
end
|
2691
|
-
else
|
2692
|
-
if name[:if_exists]
|
2693
|
-
IBM_DB.exec(@adapter.connection, sql)
|
2694
|
-
else
|
2695
|
-
begin
|
2696
|
-
if stmt = IBM_DB.exec(@adapter.connection, sql)
|
2697
|
-
stmt # Return the statement object
|
2698
|
-
else
|
2699
|
-
raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
|
2700
|
-
end
|
2701
|
-
rescue StandardError => exec_err
|
2702
|
-
if exec_err && !exec_err.message.empty?
|
2703
|
-
raise "Failed to execute statement due to: #{exec_err}"
|
2704
|
-
else
|
2705
|
-
raise
|
2706
|
-
end
|
2707
|
-
end
|
2708
|
-
end
|
2709
|
-
end
|
2710
3118
|
end
|
2711
3119
|
|
2712
3120
|
def set_schema(schema)
|
3121
|
+
@adapter.puts_log "set_schema"
|
2713
3122
|
@adapter.execute("SET SCHEMA #{schema}")
|
2714
3123
|
end
|
2715
3124
|
|
2716
|
-
def query_offset_limit(sql, offset, limit)
|
2717
|
-
end
|
2718
|
-
|
2719
|
-
def get_limit_offset_clauses(limit, offset)
|
2720
|
-
end
|
2721
|
-
|
2722
|
-
def query_offset_limit!(sql, offset, limit, options)
|
2723
|
-
end
|
2724
|
-
|
2725
3125
|
def get_datetime_mapping
|
2726
3126
|
end
|
2727
3127
|
|
@@ -2761,10 +3161,12 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2761
3161
|
end
|
2762
3162
|
|
2763
3163
|
def rename_column(table_name, column_name, new_column_name)
|
3164
|
+
@adapter.puts_log "primary_key_definition"
|
2764
3165
|
raise NotImplementedError, "rename_column is not implemented yet in the IBM_DB Adapter"
|
2765
3166
|
end
|
2766
3167
|
|
2767
3168
|
def primary_key_definition(start_id)
|
3169
|
+
@adapter.puts_log "108"
|
2768
3170
|
return "INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH #{start_id}) PRIMARY KEY NOT NULL"
|
2769
3171
|
end
|
2770
3172
|
|
@@ -2773,6 +3175,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2773
3175
|
# The "stmt" parameter is ignored for DB2 but used for IDS
|
2774
3176
|
def last_generated_id(stmt)
|
2775
3177
|
# Queries the db to obtain the last ID that was automatically generated
|
3178
|
+
@adapter.puts_log "last_generated_id"
|
2776
3179
|
sql = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1"
|
2777
3180
|
stmt = IBM_DB.prepare(@adapter.connection, sql)
|
2778
3181
|
if(stmt)
|
@@ -2781,7 +3184,8 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2781
3184
|
# Fetches the only record available (containing the last id)
|
2782
3185
|
IBM_DB.fetch_row(stmt)
|
2783
3186
|
# Retrieves and returns the result of the query with the last id.
|
2784
|
-
IBM_DB.result(stmt,0)
|
3187
|
+
id_value = IBM_DB.result(stmt,0)
|
3188
|
+
return id_value.to_i
|
2785
3189
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
2786
3190
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
2787
3191
|
if error_msg && !error_msg.empty?
|
@@ -2815,33 +3219,54 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2815
3219
|
end
|
2816
3220
|
|
2817
3221
|
def change_column(table_name, column_name, type, options)
|
2818
|
-
|
2819
|
-
|
2820
|
-
else
|
3222
|
+
@adapter.puts_log "change_column #{table_name.to_s}, #{column_name.to_s}, #{type.to_s}"
|
3223
|
+
column = @adapter.column_for(table_name, column_name)
|
2821
3224
|
data_type = @adapter.type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2828
|
-
|
2829
|
-
|
2830
|
-
|
3225
|
+
|
3226
|
+
if column.sql_type != data_type
|
3227
|
+
begin
|
3228
|
+
execute "ALTER TABLE #{table_name} ALTER #{column_name} SET DATA TYPE #{data_type}"
|
3229
|
+
rescue StandardError => exec_err
|
3230
|
+
if exec_err.message.include?('SQLCODE=-190')
|
3231
|
+
raise StatementInvalid,
|
3232
|
+
"Please consult documentation for compatible data types while changing column datatype. \
|
3233
|
+
The column datatype change to [#{data_type}] is not supported by this data server: #{exec_err}"
|
3234
|
+
else
|
3235
|
+
raise "#{exec_err}"
|
3236
|
+
end
|
2831
3237
|
end
|
3238
|
+
reorg_table(table_name)
|
3239
|
+
end
|
3240
|
+
|
3241
|
+
if options.key?(:default)
|
3242
|
+
change_column_default(table_name, column_name, options[:default])
|
3243
|
+
end
|
3244
|
+
if options.key?(:null)
|
3245
|
+
change_column_null(table_name, column_name, options[:null], nil)
|
3246
|
+
end
|
3247
|
+
end
|
3248
|
+
|
3249
|
+
def extract_new_default_value(default_or_changes)
|
3250
|
+
@adapter.puts_log "extract_new_default_value"
|
3251
|
+
if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
|
3252
|
+
default_or_changes[:to]
|
3253
|
+
else
|
3254
|
+
default_or_changes
|
2832
3255
|
end
|
2833
|
-
reorg_table(table_name)
|
2834
|
-
change_column_null(table_name,column_name,options[:null],nil)
|
2835
|
-
change_column_default(table_name, column_name, options[:default])
|
2836
|
-
reorg_table(table_name)
|
2837
3256
|
end
|
2838
|
-
end
|
2839
3257
|
|
2840
3258
|
# DB2 specific ALTER TABLE statement to add a default clause
|
2841
3259
|
def change_column_default(table_name, column_name, default)
|
3260
|
+
@adapter.puts_log "change_column_default #{table_name.to_s} #{column_name.to_s}"
|
3261
|
+
@adapter.puts_log "Default: #{default}"
|
3262
|
+
|
3263
|
+
default = extract_new_default_value(default)
|
2842
3264
|
# SQL statement which alters column's default value
|
2843
|
-
|
2844
|
-
SET WITH DEFAULT
|
3265
|
+
if default.nil?
|
3266
|
+
change_column_sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT NULL"
|
3267
|
+
else
|
3268
|
+
change_column_sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{@adapter.quote(default)}"
|
3269
|
+
end
|
2845
3270
|
|
2846
3271
|
stmt = execute(change_column_sql)
|
2847
3272
|
reorg_table(table_name)
|
@@ -2851,6 +3276,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2851
3276
|
|
2852
3277
|
#DB2 specific ALTER TABLE statement to change the nullability of a column
|
2853
3278
|
def change_column_null(table_name, column_name, null, default)
|
3279
|
+
@adapter.puts_log "change_column_null #{table_name.to_s} #{column_name.to_s}"
|
2854
3280
|
if !default.nil?
|
2855
3281
|
change_column_default(table_name, column_name, default)
|
2856
3282
|
end
|
@@ -2872,131 +3298,47 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2872
3298
|
# This method returns the DB2 SQL type corresponding to the Rails
|
2873
3299
|
# datetime/timestamp type
|
2874
3300
|
def get_datetime_mapping
|
3301
|
+
@adapter.puts_log "get_datetime_mapping"
|
2875
3302
|
return "timestamp"
|
2876
3303
|
end
|
2877
3304
|
|
2878
3305
|
# This method returns the DB2 SQL type corresponding to the Rails
|
2879
3306
|
# time type
|
2880
3307
|
def get_time_mapping
|
3308
|
+
@adapter.puts_log "get_time_mapping"
|
2881
3309
|
return "time"
|
2882
3310
|
end
|
2883
3311
|
|
2884
3312
|
#This method returns the DB2 SQL type corresponding to Rails double type
|
2885
3313
|
def get_double_mapping
|
3314
|
+
@adapter.puts_log "get_double_mapping"
|
2886
3315
|
return "double"
|
2887
3316
|
end
|
2888
3317
|
|
2889
|
-
def get_limit_offset_clauses(limit, offset)
|
2890
|
-
retHash = {"endSegment"=> "", "startSegment" => ""}
|
2891
|
-
if(offset.nil? && limit.nil?)
|
2892
|
-
return retHash
|
2893
|
-
end
|
2894
|
-
|
2895
|
-
|
2896
|
-
if (offset.nil?)
|
2897
|
-
retHash["endSegment"] = " FETCH FIRST #{limit} ROWS ONLY"
|
2898
|
-
return retHash
|
2899
|
-
end
|
2900
|
-
|
2901
|
-
#if(limit.nil?)
|
2902
|
-
if(limit.nil?)
|
2903
|
-
#retHash["startSegment"] = "SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM ( SELECT "
|
2904
|
-
retHash["startSegment"] = "SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM ( "
|
2905
|
-
retHash["endSegment"] = " ) AS I) AS O WHERE sys_row_num > #{offset}"
|
2906
|
-
return retHash
|
2907
|
-
end
|
2908
|
-
|
2909
|
-
# Defines what will be the last record
|
2910
|
-
last_record = offset.to_i + limit.to_i
|
2911
|
-
#retHash["startSegment"] = "SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM ( SELECT "
|
2912
|
-
retHash["startSegment"] = "SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM ( "
|
2913
|
-
|
2914
|
-
if last_record < offset+1
|
2915
|
-
retHash["endSegment"] = " ) AS I) AS O WHERE sys_row_num BETWEEN #{last_record} AND #{offset+1}"
|
2916
|
-
else
|
2917
|
-
retHash["endSegment"] = " ) AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
|
2918
|
-
end
|
2919
|
-
|
2920
|
-
return retHash
|
2921
|
-
end
|
2922
|
-
|
2923
|
-
def query_offset_limit(sql, offset, limit)
|
2924
|
-
if(offset.nil? && limit.nil?)
|
2925
|
-
return sql
|
2926
|
-
end
|
2927
|
-
|
2928
|
-
if (offset.nil?)
|
2929
|
-
return sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2930
|
-
end
|
2931
|
-
|
2932
|
-
if(limit.nil?)
|
2933
|
-
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2934
|
-
return sql << ") AS I) AS O WHERE sys_row_num > #{offset}"
|
2935
|
-
end
|
2936
|
-
|
2937
|
-
# Defines what will be the last record
|
2938
|
-
last_record = offset + limit
|
2939
|
-
# Transforms the SELECT query in order to retrieve/fetch only
|
2940
|
-
# a number of records after the specified offset.
|
2941
|
-
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
2942
|
-
# to select with the condition of this column being between offset+1 and the offset+limit
|
2943
|
-
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2944
|
-
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
2945
|
-
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
2946
|
-
sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
|
2947
|
-
end
|
2948
|
-
|
2949
|
-
def query_offset_limit!(sql, offset, limit, options)
|
2950
|
-
if(offset.nil? && limit.nil?)
|
2951
|
-
options[:paramArray] = []
|
2952
|
-
return sql
|
2953
|
-
end
|
2954
|
-
|
2955
|
-
if (offset.nil?)
|
2956
|
-
options[:paramArray] = []
|
2957
|
-
return sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2958
|
-
end
|
2959
|
-
|
2960
|
-
if(limit.nil?)
|
2961
|
-
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2962
|
-
sql << ") AS I) AS O WHERE sys_row_num > ?"
|
2963
|
-
options[:paramArray] = [offset]
|
2964
|
-
return
|
2965
|
-
end
|
2966
|
-
|
2967
|
-
# Defines what will be the last record
|
2968
|
-
last_record = offset + limit
|
2969
|
-
# Transforms the SELECT query in order to retrieve/fetch only
|
2970
|
-
# a number of records after the specified offset.
|
2971
|
-
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
2972
|
-
# to select with the condition of this column being between offset+1 and the offset+limit
|
2973
|
-
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2974
|
-
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
2975
|
-
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
2976
|
-
sql << ") AS I) AS O WHERE sys_row_num BETWEEN ? AND ?"
|
2977
|
-
options[:paramArray] = [offset+1, last_record]
|
2978
|
-
end
|
2979
|
-
|
2980
3318
|
# This method generates the default blob value specified for
|
2981
3319
|
# DB2 Dataservers
|
2982
3320
|
def set_binary_default(value)
|
3321
|
+
@adapter.puts_log "set_binary_default"
|
2983
3322
|
"BLOB('#{value}')"
|
2984
3323
|
end
|
2985
3324
|
|
2986
3325
|
# This method generates the blob value specified for DB2 Dataservers
|
2987
3326
|
def set_binary_value
|
3327
|
+
@adapter.puts_log "set_binary_value"
|
2988
3328
|
"BLOB('?')"
|
2989
3329
|
end
|
2990
3330
|
|
2991
3331
|
# This method generates the default clob value specified for
|
2992
3332
|
# DB2 Dataservers
|
2993
3333
|
def set_text_default(value)
|
3334
|
+
@adapter.puts_log "set_text_default"
|
2994
3335
|
"'#{value}'"
|
2995
3336
|
end
|
2996
3337
|
|
2997
3338
|
# For DB2 Dataservers , the arguments to the meta-data functions
|
2998
3339
|
# need to be in upper-case
|
2999
3340
|
def set_case(value)
|
3341
|
+
@adapter.puts_log "set_case"
|
3000
3342
|
value.upcase
|
3001
3343
|
end
|
3002
3344
|
end # class IBM_DB2
|
@@ -3059,6 +3401,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
3059
3401
|
if rfile
|
3060
3402
|
RESERVED_WORDS = open(rfile.to_s) {|f| YAML.load(f) }
|
3061
3403
|
def check_reserved_words(col_name)
|
3404
|
+
puts_log "164"
|
3062
3405
|
if RESERVED_WORDS[col_name]
|
3063
3406
|
'"' + RESERVED_WORDS[col_name] + '"'
|
3064
3407
|
else
|
@@ -3140,28 +3483,6 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
3140
3483
|
class IBM_DB2_ZOS_8 < IBM_DB2_ZOS
|
3141
3484
|
include HostedDataServer
|
3142
3485
|
|
3143
|
-
def get_limit_offset_clauses(limit, offset)
|
3144
|
-
retHash = {"startSegment" => "", "endSegment" => ""}
|
3145
|
-
if (!limit.nil?)
|
3146
|
-
retHash["endSegment"] = " FETCH FIRST #{limit} ROWS ONLY"
|
3147
|
-
end
|
3148
|
-
return retHash
|
3149
|
-
end
|
3150
|
-
|
3151
|
-
def query_offset_limit(sql, offset, limit)
|
3152
|
-
if (!limit.nil?)
|
3153
|
-
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
3154
|
-
end
|
3155
|
-
return sql
|
3156
|
-
end
|
3157
|
-
|
3158
|
-
def query_offset_limit!(sql, offset, limit, options)
|
3159
|
-
if (!limit.nil?)
|
3160
|
-
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
3161
|
-
end
|
3162
|
-
options[:paramArray] = []
|
3163
|
-
end
|
3164
|
-
|
3165
3486
|
# This call is needed on DB2 z/OS v8 for the creation of tables
|
3166
3487
|
# with LOBs. When issued, this call does the following:
|
3167
3488
|
# DB2 creates LOB table spaces, auxiliary tables, and indexes on auxiliary
|
@@ -3310,56 +3631,6 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
3310
3631
|
return "double precision"
|
3311
3632
|
end
|
3312
3633
|
|
3313
|
-
def get_limit_offset_clauses(limit, offset)
|
3314
|
-
retHash = {"startSegment" => "", "endSegment" => ""}
|
3315
|
-
if limit != 0
|
3316
|
-
if !offset.nil?
|
3317
|
-
# Modifying the SQL to utilize the skip and limit amounts
|
3318
|
-
retHash["startSegment"] = " SELECT SKIP #{offset} LIMIT #{limit} "
|
3319
|
-
else
|
3320
|
-
# Modifying the SQL to retrieve only the first #{limit} rows
|
3321
|
-
retHash["startSegment"] = " SELECT FIRST #{limit} "
|
3322
|
-
end
|
3323
|
-
else
|
3324
|
-
retHash["startSegment"] = " SELECT * FROM (SELECT "
|
3325
|
-
retHash["endSegment"] = " ) WHERE 0 = 1 "
|
3326
|
-
end
|
3327
|
-
end
|
3328
|
-
|
3329
|
-
# Handling offset/limit as per Informix requirements
|
3330
|
-
def query_offset_limit(sql, offset, limit)
|
3331
|
-
if limit != 0
|
3332
|
-
if !offset.nil?
|
3333
|
-
# Modifying the SQL to utilize the skip and limit amounts
|
3334
|
-
sql.gsub!(/SELECT/i,"SELECT SKIP #{offset} LIMIT #{limit}")
|
3335
|
-
else
|
3336
|
-
# Modifying the SQL to retrieve only the first #{limit} rows
|
3337
|
-
sql = sql.gsub!("SELECT","SELECT FIRST #{limit}")
|
3338
|
-
end
|
3339
|
-
else
|
3340
|
-
# Modifying the SQL to ensure that no rows will be returned
|
3341
|
-
sql.gsub!(/SELECT/i,"SELECT * FROM (SELECT")
|
3342
|
-
sql << ") WHERE 0 = 1"
|
3343
|
-
end
|
3344
|
-
end
|
3345
|
-
|
3346
|
-
# Handling offset/limit as per Informix requirements
|
3347
|
-
def query_offset_limit!(sql, offset, limit, options)
|
3348
|
-
if limit != 0
|
3349
|
-
if !offset.nil?
|
3350
|
-
# Modifying the SQL to utilize the skip and limit amounts
|
3351
|
-
sql.gsub!(/SELECT/i,"SELECT SKIP #{offset} LIMIT #{limit}")
|
3352
|
-
else
|
3353
|
-
# Modifying the SQL to retrieve only the first #{limit} rows
|
3354
|
-
sql = sql.gsub!("SELECT","SELECT FIRST #{limit}")
|
3355
|
-
end
|
3356
|
-
else
|
3357
|
-
# Modifying the SQL to ensure that no rows will be returned
|
3358
|
-
sql.gsub!(/SELECT/i,"SELECT * FROM (SELECT")
|
3359
|
-
sql << ") WHERE 0 = 1"
|
3360
|
-
end
|
3361
|
-
end
|
3362
|
-
|
3363
3634
|
# Method that returns the last automatically generated ID
|
3364
3635
|
# on the given +@connection+. This method is required by the +insert+
|
3365
3636
|
# method. IDS returns the last generated serial value in the SQLCA unlike
|
@@ -3406,72 +3677,73 @@ end # module ActiveRecord
|
|
3406
3677
|
|
3407
3678
|
module Arel
|
3408
3679
|
#Check Arel version
|
3409
|
-
|
3410
|
-
|
3411
|
-
|
3412
|
-
|
3413
|
-
|
3414
|
-
if(arelVersion >= 6)
|
3415
|
-
module Collectors
|
3416
|
-
|
3417
|
-
|
3418
|
-
|
3419
|
-
|
3680
|
+
begin
|
3681
|
+
arelVersion = Arel::VERSION.to_i
|
3682
|
+
rescue
|
3683
|
+
arelVersion = 0
|
3684
|
+
end
|
3685
|
+
if(arelVersion >= 6)
|
3686
|
+
module Collectors
|
3687
|
+
class Bind
|
3688
|
+
def changeFirstSegment(segment)
|
3689
|
+
@parts[0] = segment
|
3690
|
+
end
|
3420
3691
|
|
3421
|
-
|
3422
|
-
|
3423
|
-
|
3692
|
+
def changeEndSegment(segment)
|
3693
|
+
len = @parts.length
|
3694
|
+
@parts[len] = segment
|
3695
|
+
end
|
3424
3696
|
end
|
3425
3697
|
end
|
3426
3698
|
end
|
3427
|
-
end
|
3428
3699
|
|
3429
3700
|
module Visitors
|
3430
3701
|
class Visitor #opening and closing the class to ensure backward compatibility
|
3431
3702
|
end
|
3432
3703
|
|
3433
|
-
#Check Arel version
|
3434
|
-
|
3435
|
-
|
3436
|
-
|
3437
|
-
|
3438
|
-
|
3439
|
-
|
3440
|
-
|
3441
|
-
|
3442
|
-
|
3704
|
+
#Check Arel version
|
3705
|
+
begin
|
3706
|
+
arelVersion = Arel::VERSION.to_i
|
3707
|
+
rescue
|
3708
|
+
arelVersion = 0
|
3709
|
+
end
|
3710
|
+
|
3711
|
+
if(arelVersion >= 6 && arelVersion <= 9)
|
3712
|
+
class ToSql < Arel::Visitors::Reduce #opening and closing the class to ensure backward compatibility
|
3713
|
+
# In case when using Rails-2.3.x there is no arel used due to which the constructor has to be defined explicitly
|
3714
|
+
# to ensure the same code works on any version of Rails
|
3443
3715
|
|
3444
|
-
|
3445
|
-
|
3446
|
-
|
3447
|
-
|
3448
|
-
|
3449
|
-
|
3716
|
+
#Check Arel version
|
3717
|
+
begin
|
3718
|
+
@arelVersion = Arel::VERSION.to_i
|
3719
|
+
rescue
|
3720
|
+
@arelVersion = 0
|
3721
|
+
end
|
3450
3722
|
|
3451
|
-
|
3452
|
-
|
3453
|
-
|
3454
|
-
|
3455
|
-
|
3456
|
-
|
3457
|
-
|
3458
|
-
|
3723
|
+
if(@arelVersion >= 3)
|
3724
|
+
def initialize connection
|
3725
|
+
super()
|
3726
|
+
@connection = connection
|
3727
|
+
@schema_cache = connection.schema_cache if(connection.respond_to?(:schema_cache))
|
3728
|
+
@quoted_tables = {}
|
3729
|
+
@quoted_columns = {}
|
3730
|
+
@last_column = nil
|
3731
|
+
end
|
3459
3732
|
end
|
3460
3733
|
end
|
3461
|
-
|
3462
|
-
|
3463
|
-
|
3464
|
-
|
3465
|
-
# to ensure the same code works on any version of Rails
|
3734
|
+
else
|
3735
|
+
class ToSql < Arel::Visitors::Visitor #opening and closing the class to ensure backward compatibility
|
3736
|
+
# In case when using Rails-2.3.x there is no arel used due to which the constructor has to be defined explicitly
|
3737
|
+
# to ensure the same code works on any version of Rails
|
3466
3738
|
|
3467
3739
|
#Check Arel version
|
3468
|
-
|
3469
|
-
|
3740
|
+
begin
|
3741
|
+
@arelVersion = Arel::VERSION.to_i
|
3470
3742
|
rescue
|
3471
3743
|
@arelVersion = 0
|
3472
3744
|
end
|
3473
|
-
|
3474
|
-
|
3745
|
+
if(@arelVersion >= 3)
|
3746
|
+
def initialize connection
|
3475
3747
|
super()
|
3476
3748
|
@connection = connection
|
3477
3749
|
@schema_cache = connection.schema_cache if(connection.respond_to?(:schema_cache))
|
@@ -3482,42 +3754,42 @@ else
|
|
3482
3754
|
|
3483
3755
|
end
|
3484
3756
|
end
|
3485
|
-
|
3486
|
-
end
|
3487
|
-
|
3488
|
-
|
3489
|
-
class IBM_DB < Arel::Visitors::ToSql
|
3490
|
-
private
|
3757
|
+
end
|
3491
3758
|
|
3492
|
-
|
3493
|
-
|
3494
|
-
|
3759
|
+
class IBM_DB < Arel::Visitors::ToSql
|
3760
|
+
private
|
3761
|
+
def visit_Arel_Nodes_Limit(o, collector)
|
3762
|
+
collector << " FETCH FIRST "
|
3495
3763
|
visit o.expr, collector
|
3496
|
-
|
3764
|
+
collector << " ROWS ONLY "
|
3497
3765
|
end
|
3498
3766
|
|
3499
|
-
def visit_Arel_Nodes_Offset
|
3500
|
-
|
3767
|
+
def visit_Arel_Nodes_Offset(o, collector)
|
3768
|
+
collector << " OFFSET "
|
3769
|
+
visit o.expr, collector
|
3770
|
+
collector << " ROWS"
|
3501
3771
|
end
|
3772
|
+
|
3502
3773
|
def visit_Arel_Nodes_ValuesList(o, collector)
|
3503
|
-
|
3504
|
-
|
3505
|
-
|
3506
|
-
|
3507
|
-
|
3508
|
-
|
3509
|
-
|
3510
|
-
|
3511
|
-
|
3512
|
-
|
3513
|
-
|
3514
|
-
|
3515
|
-
end
|
3774
|
+
collector << "VALUES "
|
3775
|
+
o.rows.each_with_index do |row, i|
|
3776
|
+
collector << ", " unless i == 0
|
3777
|
+
collector << "("
|
3778
|
+
row.each_with_index do |value, k|
|
3779
|
+
collector << ", " unless k == 0
|
3780
|
+
case value
|
3781
|
+
when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
|
3782
|
+
collector = visit(value, collector)
|
3783
|
+
#collector << quote(value).to_s
|
3784
|
+
else
|
3785
|
+
collector << quote(value).to_s
|
3516
3786
|
end
|
3517
|
-
collector << ")"
|
3518
3787
|
end
|
3519
|
-
collector
|
3788
|
+
collector << ")"
|
3789
|
+
end
|
3790
|
+
collector
|
3520
3791
|
end
|
3792
|
+
|
3521
3793
|
def visit_Arel_Nodes_SelectStatement o, collector
|
3522
3794
|
if o.with
|
3523
3795
|
collector = visit o.with, collector
|
@@ -3533,61 +3805,27 @@ end
|
|
3533
3805
|
len = o.orders.length - 1
|
3534
3806
|
o.orders.each_with_index { |x, i|
|
3535
3807
|
collector = visit(x, collector)
|
3536
|
-
collector << "," unless len == i
|
3808
|
+
collector << ", " unless len == i
|
3537
3809
|
}
|
3538
3810
|
end
|
3539
3811
|
|
3540
|
-
|
3541
|
-
|
3542
|
-
|
3543
|
-
|
3544
|
-
|
3545
|
-
|
3546
|
-
|
3547
|
-
|
3548
|
-
|
3549
|
-
|
3550
|
-
|
3551
|
-
|
3552
|
-
|
3553
|
-
#
|
3554
|
-
|
3555
|
-
|
3556
|
-
#
|
3557
|
-
# limOffClause = @connection.get_limit_offset_clauses(limit,offset)
|
3558
|
-
#
|
3559
|
-
# if( !limOffClause["startSegment"].empty? )
|
3560
|
-
# #collector.changeFirstSegment(limOffClause["startSegment"])
|
3561
|
-
# collector.value.prepend(limOffClause["startSegment"])
|
3562
|
-
# end
|
3563
|
-
#
|
3564
|
-
# if( !limOffClause["endSegment"].empty? )
|
3565
|
-
# #collector.changeEndSegment(limOffClause["endSegment"])
|
3566
|
-
# collector << " "
|
3567
|
-
# collector << limOffClause["endSegment"]
|
3568
|
-
# end
|
3569
|
-
|
3570
|
-
#Initialize a new Collector and set its value to the sql string built so far with any limit and ofset modifications
|
3571
|
-
#collector.reset(sql)
|
3572
|
-
if (o.limit && o.offset.nil?)
|
3573
|
-
visit(o.limit, collector)
|
3574
|
-
end
|
3575
|
-
if (o.offset && o.limit.nil?)
|
3576
|
-
collector.value.prepend(" SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM ( ")
|
3577
|
-
collector << (" ) AS I) AS O WHERE sys_row_num > ")
|
3578
|
-
visit(o.offset, collector)
|
3579
|
-
end
|
3580
|
-
|
3581
|
-
if (o.offset && o.limit)
|
3582
|
-
collector.value.prepend(" SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM ( ")
|
3583
|
-
collector << (" ) AS I) AS O WHERE sys_row_num > ")
|
3584
|
-
visit(o.offset, collector)
|
3585
|
-
visit(o.limit, collector)
|
3586
|
-
end
|
3587
|
-
collector = maybe_visit o.lock, collector
|
3588
|
-
return collector
|
3812
|
+
if (o.offset && o.limit)
|
3813
|
+
visit_Arel_Nodes_Offset(o.offset, collector)
|
3814
|
+
visit_Arel_Nodes_Limit(o.limit, collector)
|
3815
|
+
elsif (o.offset && o.limit.nil?)
|
3816
|
+
collector << " OFFSET "
|
3817
|
+
visit o.offset.expr, collector
|
3818
|
+
collector << " ROWS "
|
3819
|
+
maybe_visit o.lock, collector
|
3820
|
+
else
|
3821
|
+
visit_Arel_Nodes_SelectOptions(o, collector)
|
3822
|
+
end
|
3823
|
+
end
|
3824
|
+
|
3825
|
+
# Locks are not supported in SQLite
|
3826
|
+
def visit_Arel_Nodes_Lock(o, collector)
|
3827
|
+
collector
|
3589
3828
|
end
|
3590
|
-
|
3591
3829
|
end
|
3592
3830
|
end
|
3593
3831
|
end
|