ibm_db 5.2.0-x86-mingw32 → 5.3.2-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/ext/Makefile +15 -13
- data/ext/ibm_db.c +62 -57
- 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 +1463 -1279
- data/lib/ibm_db.so +1 -0
- data/lib/mswin32/rb3x/i386/ruby30/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 +190 -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,190 @@ 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 default_primary_key?(column)
|
55
|
+
schema_type(column) == :integer
|
56
|
+
end
|
65
57
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
58
|
+
def explicit_primary_key_default?(column)
|
59
|
+
column.bigint? and column.name == 'id'
|
60
|
+
end
|
61
|
+
end
|
70
62
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
63
|
+
class SchemaCreation
|
64
|
+
private
|
65
|
+
def visit_TableDefinition(o)
|
66
|
+
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
67
|
+
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
68
|
+
create_sql << "#{quote_table_name(o.name)} "
|
76
69
|
|
77
|
-
|
78
|
-
|
70
|
+
statements = o.columns.map { |c| accept c }
|
71
|
+
statements << accept(o.primary_keys) if o.primary_keys
|
79
72
|
|
80
|
-
|
73
|
+
if supports_indexes_in_create?
|
74
|
+
statements.concat(o.indexes.map { |column_name, options| index_in_create(o.name, column_name, options) })
|
75
|
+
end
|
81
76
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
end
|
77
|
+
if supports_foreign_keys?
|
78
|
+
statements.concat(o.foreign_keys.map { |to_table, options| foreign_key_in_create(o.name, to_table, options) })
|
79
|
+
end
|
86
80
|
|
87
|
-
|
88
|
-
|
89
|
-
|
81
|
+
if supports_check_constraints?
|
82
|
+
statements.concat(o.check_constraints.map { |expression, options| check_constraint_in_create(o.name, expression, options) })
|
83
|
+
end
|
90
84
|
|
91
|
-
|
85
|
+
create_sql << "(#{statements.join(', ')})" if statements.present?
|
86
|
+
add_table_options!(create_sql, o)
|
87
|
+
create_sql << " AS (#{to_sql(o.as)}) WITH DATA" if o.as
|
88
|
+
create_sql
|
89
|
+
end
|
92
90
|
|
91
|
+
def add_column_options!(sql, options)
|
92
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
93
|
+
if options[:auto_increment] == true
|
94
|
+
sql << " GENERATED BY DEFAULT AS IDENTITY (START WITH 1000)"
|
95
|
+
end
|
96
|
+
if options[:primary_key] == true
|
97
|
+
sql << " PRIMARY KEY"
|
98
|
+
end
|
99
|
+
# must explicitly check for :null to allow change_column to work on migrations
|
100
|
+
if options[:null] == false
|
101
|
+
sql << " NOT NULL"
|
102
|
+
end
|
103
|
+
sql
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Relation
|
93
109
|
|
94
|
-
|
95
|
-
|
96
|
-
else
|
97
|
-
im.insert substitutes
|
98
|
-
end
|
99
|
-
conn.insert(
|
100
|
-
im,
|
101
|
-
'SQL',
|
102
|
-
primary_key,
|
103
|
-
primary_key_value,
|
104
|
-
nil,
|
105
|
-
binds)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
|
110
|
+
def insert(values)
|
111
|
+
primary_key_value = nil
|
110
112
|
|
111
|
-
|
113
|
+
if primary_key && Hash === values
|
114
|
+
primary_key_value = values[values.keys.find { |k|
|
115
|
+
k.name == primary_key
|
116
|
+
}]
|
117
|
+
|
118
|
+
if !primary_key_value && connection.prefetch_primary_key?(klass.table_name)
|
119
|
+
primary_key_value = connection.next_sequence_value(klass.sequence_name)
|
120
|
+
values[klass.arel_table[klass.primary_key]] = primary_key_value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
im = arel.create_insert
|
125
|
+
im.into @table
|
126
|
+
|
127
|
+
conn = @klass.connection
|
128
|
+
substitutes = values.sort_by { |arel_attr,_| arel_attr.name }
|
129
|
+
binds = substitutes.map do |arel_attr, value|
|
130
|
+
[@klass.columns_hash[arel_attr.name], value]
|
131
|
+
end
|
132
|
+
|
133
|
+
substitutes, binds = substitute_values values
|
134
|
+
if values.empty? # empty insert
|
135
|
+
im.values = Arel.sql(connection.empty_insert_statement_value(klass.primary_key, klass.table_name))
|
136
|
+
else
|
137
|
+
im.insert substitutes
|
138
|
+
end
|
139
|
+
|
140
|
+
conn.insert(im, 'SQL', primary_key, primary_key_value, nil, binds)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Base
|
112
145
|
# Method required to handle LOBs and XML fields.
|
113
146
|
# An after save callback checks if a marker has been inserted through
|
114
147
|
# the insert or update, and then proceeds to update that record with
|
115
148
|
# the actual large object through a prepared statement (param binding).
|
116
149
|
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
|
-
|
150
|
+
def handle_lobs()
|
151
|
+
if self.class.connection.kind_of?(ConnectionAdapters::IBM_DBAdapter)
|
152
|
+
# Checks that the insert or update had at least a BLOB, CLOB or XML field
|
153
|
+
self.class.connection.sql.each do |clob_sql|
|
154
|
+
if clob_sql =~ /BLOB\('(.*)'\)/i ||
|
155
|
+
clob_sql =~ /@@@IBMTEXT@@@/i ||
|
156
|
+
clob_sql =~ /@@@IBMXML@@@/i ||
|
157
|
+
clob_sql =~ /@@@IBMBINARY@@@/i
|
158
|
+
update_query = "UPDATE #{self.class.table_name} SET ("
|
159
|
+
counter = 0
|
160
|
+
values = []
|
161
|
+
params = []
|
162
|
+
# Selects only binary, text and xml columns
|
163
|
+
self.class.columns.select{|col| col.sql_type.to_s =~ /blob|binary|clob|text|xml/i }.each do |col|
|
164
|
+
if counter == 0
|
165
|
+
update_query << "#{col.name}"
|
166
|
+
else
|
167
|
+
update_query << ",#{col.name}"
|
168
|
+
end
|
169
|
+
|
170
|
+
# Add a '?' for the parameter or a NULL if the value is nil or empty
|
171
|
+
# (except for a CLOB field where '' can be a value)
|
172
|
+
if self[col.name].nil? ||
|
173
|
+
self[col.name] == {} ||
|
174
|
+
self[col.name] == [] ||
|
175
|
+
(self[col.name] == '' && !(col.sql_type.to_s =~ /text|clob/i))
|
176
|
+
params << 'NULL'
|
177
|
+
else
|
178
|
+
if (col.cast_type.is_a?(::ActiveRecord::Type::Serialized))
|
179
|
+
values << YAML.dump(self[col.name])
|
180
|
+
else
|
181
|
+
values << self[col.name]
|
182
|
+
end
|
183
|
+
params << '?'
|
184
|
+
end
|
185
|
+
counter += 1
|
186
|
+
end
|
187
|
+
|
188
|
+
# no subsequent update is required if no relevant columns are found
|
189
|
+
next if counter == 0
|
190
|
+
|
191
|
+
update_query << ") = "
|
192
|
+
# IBM_DB accepts 'SET (column) = NULL' but not (NULL),
|
193
|
+
# therefore the sql needs to be changed for a single NULL field.
|
194
|
+
if params.size==1 && params[0] == 'NULL'
|
195
|
+
update_query << "NULL"
|
196
|
+
else
|
197
|
+
update_query << "(" + params.join(',') + ")"
|
198
|
+
end
|
199
|
+
|
200
|
+
update_query << " WHERE #{self.class.primary_key} = ?"
|
201
|
+
values << self[self.class.primary_key.downcase]
|
169
202
|
|
170
203
|
begin
|
171
204
|
unless stmt = IBM_DB.prepare(self.class.connection.connection, update_query)
|
@@ -176,14 +209,15 @@ module ActiveRecord
|
|
176
209
|
raise StandardError.new('An unexpected error occurred during update of LOB/XML column')
|
177
210
|
end
|
178
211
|
end
|
179
|
-
|
212
|
+
|
213
|
+
self.class.connection.log_query(update_query,'update of LOB/XML field(s)in handle_lobs')
|
180
214
|
|
181
215
|
# rollback any failed LOB/XML field updates (and remove associated marker)
|
182
216
|
unless IBM_DB.execute(stmt, values)
|
183
217
|
error_msg = "Failed to insert/update LOB/XML field(s) due to: #{IBM_DB.getErrormsg( stmt, IBM_DB::DB_STMT )}"
|
184
218
|
self.class.connection.execute("ROLLBACK")
|
185
219
|
raise error_msg
|
186
|
-
|
220
|
+
end
|
187
221
|
rescue StandardError => error
|
188
222
|
raise error
|
189
223
|
ensure
|
@@ -194,8 +228,8 @@ module ActiveRecord
|
|
194
228
|
self.class.connection.handle_lobs_triggered = true
|
195
229
|
end # if connection.kind_of?
|
196
230
|
end # handle_lobs
|
197
|
-
private :handle_lobs
|
198
231
|
|
232
|
+
private :handle_lobs
|
199
233
|
|
200
234
|
# Establishes a connection to a specified database using the credentials provided
|
201
235
|
# with the +config+ argument. All the ActiveRecord objects will use this connection
|
@@ -208,10 +242,6 @@ module ActiveRecord
|
|
208
242
|
raise LoadError, "Failed to load IBM_DB Ruby driver."
|
209
243
|
end
|
210
244
|
|
211
|
-
#if( config.has_key?(:parameterized) && config[:parameterized] == true )
|
212
|
-
# require 'active_record/connection_adapters/ibm_db_pstmt'
|
213
|
-
# end
|
214
|
-
|
215
245
|
# Check if class TableDefinition responds to indexes method to determine if we are on AR 3 or AR 4.
|
216
246
|
# 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
247
|
checkClass = ActiveRecord::ConnectionAdapters::TableDefinition.new(self,nil)
|
@@ -326,381 +356,308 @@ module ActiveRecord
|
|
326
356
|
end
|
327
357
|
end # class Base
|
328
358
|
|
329
|
-
|
330
|
-
|
331
359
|
module ConnectionAdapters
|
332
360
|
class Column
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
361
|
+
def self.binary_to_string(value)
|
362
|
+
puts_log "binary_to_string"
|
363
|
+
# Returns a string removing the eventual BLOB scalar function
|
364
|
+
value.to_s.gsub(/"SYSIBM"."BLOB"\('(.*)'\)/i,'\1')
|
365
|
+
end
|
366
|
+
end
|
338
367
|
|
339
368
|
module Quoting
|
340
|
-
|
341
|
-
|
342
|
-
|
369
|
+
def lookup_cast_type_from_column(column) # :nodoc:
|
370
|
+
lookup_cast_type(column.sql_type_metadata.sql_type)
|
371
|
+
end
|
343
372
|
end
|
344
373
|
|
345
374
|
module Savepoints
|
346
|
-
|
347
|
-
|
348
|
-
|
375
|
+
def create_savepoint(name = current_savepoint_name)
|
376
|
+
puts_log "create_savepoint"
|
377
|
+
execute("SAVEPOINT #{name} ON ROLLBACK RETAIN CURSORS", "TRANSACTION")
|
378
|
+
end
|
349
379
|
end
|
350
380
|
|
351
381
|
|
352
382
|
module ColumnDumper
|
353
383
|
def prepare_column_options(column)
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
384
|
+
puts_log "prepare_column_options"
|
385
|
+
spec = {}
|
386
|
+
|
387
|
+
if limit = schema_limit(column)
|
388
|
+
spec[:limit] = limit
|
389
|
+
end
|
390
|
+
|
391
|
+
if precision = schema_precision(column)
|
392
|
+
spec[:precision] = precision
|
393
|
+
end
|
363
394
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
default = schema_default(column) if column.has_default?
|
369
|
-
spec[:default] = default unless default.nil?
|
395
|
+
if scale = schema_scale(column)
|
396
|
+
spec[:scale] = scale
|
397
|
+
end
|
370
398
|
|
371
|
-
|
399
|
+
default = schema_default(column) if column.has_default?
|
400
|
+
spec[:default] = default unless default.nil?
|
401
|
+
spec[:null] = 'false' unless column.null
|
372
402
|
|
373
|
-
|
374
|
-
|
375
|
-
|
403
|
+
if collation = schema_collation(column)
|
404
|
+
spec[:collation] = collation
|
405
|
+
end
|
376
406
|
|
377
|
-
|
407
|
+
spec[:comment] = column.comment.inspect if column.comment.present?
|
378
408
|
|
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
|
409
|
+
spec
|
410
|
+
end
|
404
411
|
|
405
|
-
|
412
|
+
def schema_limit(column)
|
413
|
+
puts_log "schema_limit"
|
414
|
+
limit = column.limit unless column.bigint?
|
415
|
+
limit.inspect if limit && limit != native_database_types[column.type.to_sym][:limit]
|
416
|
+
end
|
417
|
+
end #end of module ColumnDumper
|
406
418
|
|
407
419
|
module SchemaStatements
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
end
|
420
|
+
|
421
|
+
def internal_string_options_for_primary_key # :nodoc:
|
422
|
+
{ primary_key: true, null: false }
|
423
|
+
end
|
413
424
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
425
|
+
def drop_table(table_name, options={})
|
426
|
+
puts_log "drop_table"
|
427
|
+
if options[:if_exists]
|
428
|
+
execute("DROP TABLE IF EXISTS #{quote_table_name(table_name)}")
|
429
|
+
else
|
430
|
+
execute("DROP TABLE #{quote_table_name(table_name)}", options)
|
431
|
+
end
|
432
|
+
end
|
418
433
|
|
419
|
-
|
420
|
-
|
421
|
-
TableDefinition.new
|
434
|
+
def create_table_definition(*args, **options)
|
435
|
+
puts_log "create_table_definition"
|
436
|
+
TableDefinition.new(self, *args, **options)
|
422
437
|
end
|
423
|
-
=end
|
424
|
-
def create_table_definition(*args, **options)
|
425
|
-
TableDefinition.new(self, *args, **options)
|
426
|
-
end
|
427
438
|
|
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
439
|
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
|
440
|
+
|
441
|
+
class IBM_DBColumn < ConnectionAdapters::Column # :nodoc:
|
442
|
+
def initialize(*)
|
443
|
+
puts_log "15"
|
473
444
|
super
|
474
445
|
end
|
475
|
-
=end
|
476
446
|
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
447
|
+
# Used to convert from BLOBs to Strings
|
448
|
+
def self.binary_to_string(value)
|
449
|
+
# Returns a string removing the eventual BLOB scalar function
|
450
|
+
value.to_s.gsub(/"SYSIBM"."BLOB"\('(.*)'\)/i,'\1')
|
451
|
+
end
|
483
452
|
end #class IBM_DBColumn
|
484
453
|
|
485
|
-
|
486
|
-
module ColumnMethods
|
487
|
-
|
454
|
+
module ColumnMethods
|
488
455
|
def primary_key(name, type = :primary_key, **options)
|
489
|
-
|
490
|
-
|
456
|
+
puts_log "16"
|
457
|
+
column(name, type, options.merge(primary_key: true))
|
458
|
+
end
|
491
459
|
|
492
|
-
|
493
|
-
|
494
|
-
|
460
|
+
##class Table
|
461
|
+
class Table < ActiveRecord::ConnectionAdapters::Table
|
462
|
+
include ColumnMethods
|
495
463
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
464
|
+
#Method to parse the passed arguments and create the ColumnDefinition object of the specified type
|
465
|
+
def ibm_parse_column_attributes_args(type, *args)
|
466
|
+
puts_log "ibm_parse_column_attributes_args"
|
467
|
+
options = {}
|
468
|
+
if args.last.is_a?(Hash)
|
469
|
+
options = args.delete_at(args.length-1)
|
470
|
+
end
|
471
|
+
args.each do | name |
|
472
|
+
column name,type.to_sym,options
|
473
|
+
end # end args.each
|
474
|
+
end
|
475
|
+
private :ibm_parse_column_attributes_args
|
507
476
|
|
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
|
477
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type xml
|
478
|
+
#This method is different as compared to def char (sql is being issued explicitly
|
479
|
+
#as compared to def char where method column(which will generate the sql is being called)
|
480
|
+
#in order to handle the DEFAULT and NULL option for the native XML datatype
|
481
|
+
def xml(*args )
|
482
|
+
puts_log "18"
|
483
|
+
options = {}
|
484
|
+
if args.last.is_a?(Hash)
|
485
|
+
options = args.delete_at(args.length-1)
|
486
|
+
end
|
487
|
+
sql_segment = "ALTER TABLE #{@base.quote_table_name(@table_name)} ADD COLUMN "
|
488
|
+
args.each do | name |
|
489
|
+
sql = sql_segment + " #{@base.quote_column_name(name)} xml"
|
490
|
+
@base.execute(sql,"add_xml_column")
|
491
|
+
end
|
492
|
+
return self
|
493
|
+
end
|
494
|
+
|
495
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type double
|
496
|
+
def double(*args)
|
497
|
+
puts_log "19"
|
498
|
+
ibm_parse_column_attributes_args('double',*args)
|
499
|
+
return self
|
500
|
+
end
|
541
501
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
502
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type decfloat
|
503
|
+
def decfloat(*args)
|
504
|
+
puts_log "20"
|
505
|
+
ibm_parse_column_attributes_args('decfloat',*args)
|
506
|
+
return self
|
507
|
+
end
|
546
508
|
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
509
|
+
def graphic(*args)
|
510
|
+
puts_log "21"
|
511
|
+
ibm_parse_column_attributes_args('graphic',*args)
|
512
|
+
return self
|
513
|
+
end
|
551
514
|
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
end
|
557
|
-
alias_method :character, :char
|
515
|
+
def vargraphic(*args)
|
516
|
+
puts_log "22"
|
517
|
+
ibm_parse_column_attributes_args('vargraphic',*args)
|
518
|
+
return self
|
558
519
|
end
|
559
520
|
|
560
|
-
|
561
|
-
|
562
|
-
|
521
|
+
def bigint(*args)
|
522
|
+
puts_log "23"
|
523
|
+
ibm_parse_column_attributes_args('bigint',*args)
|
524
|
+
return self
|
525
|
+
end
|
563
526
|
|
564
|
-
|
565
|
-
|
527
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type char [character]
|
528
|
+
def char(*args)
|
529
|
+
puts_log "24"
|
530
|
+
ibm_parse_column_attributes_args('char',*args)
|
531
|
+
return self
|
532
|
+
end
|
533
|
+
alias_method :character, :char
|
566
534
|
|
567
|
-
|
568
|
-
@ar3 = false
|
569
|
-
else
|
570
|
-
@ar3 = true
|
571
|
-
end
|
535
|
+
end # end of class Table
|
572
536
|
|
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
|
537
|
+
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
538
|
+
include ColumnMethods
|
603
539
|
|
604
|
-
|
605
|
-
|
606
|
-
|
540
|
+
def native
|
541
|
+
puts_log "25"
|
542
|
+
@base.native_database_types
|
543
|
+
end
|
607
544
|
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
args.each do | name |
|
615
|
-
column(name,type,options)
|
616
|
-
end
|
545
|
+
#Method to parse the passed arguments and create the ColumnDefinition object of the specified type
|
546
|
+
def ibm_parse_column_attributes_args(type, *args)
|
547
|
+
puts_log "26"
|
548
|
+
options = {}
|
549
|
+
if args.last.is_a?(Hash)
|
550
|
+
options = args.delete_at(args.length-1)
|
617
551
|
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
|
552
|
+
args.each do | name |
|
553
|
+
column(name,type,options)
|
624
554
|
end
|
555
|
+
end
|
556
|
+
private :ibm_parse_column_attributes_args
|
625
557
|
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
558
|
+
#Method to support the new syntax of rails 2.0 migrations for columns of type xml
|
559
|
+
def xml(*args )
|
560
|
+
puts_log "27"
|
561
|
+
ibm_parse_column_attributes_args('xml', *args)
|
562
|
+
return self
|
563
|
+
end
|
631
564
|
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
565
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type double
|
566
|
+
def double(*args)
|
567
|
+
puts_log "28"
|
568
|
+
ibm_parse_column_attributes_args('double',*args)
|
569
|
+
return self
|
570
|
+
end
|
637
571
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
572
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type decfloat
|
573
|
+
def decfloat(*args)
|
574
|
+
puts_log "29"
|
575
|
+
ibm_parse_column_attributes_args('decfloat',*args)
|
576
|
+
return self
|
577
|
+
end
|
642
578
|
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
579
|
+
def graphic(*args)
|
580
|
+
puts_log "30"
|
581
|
+
ibm_parse_column_attributes_args('graphic',*args)
|
582
|
+
return self
|
583
|
+
end
|
647
584
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
585
|
+
def vargraphic(*args)
|
586
|
+
puts_log "31"
|
587
|
+
ibm_parse_column_attributes_args('vargraphic',*args)
|
588
|
+
return self
|
589
|
+
end
|
652
590
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
591
|
+
def bigint(*args)
|
592
|
+
puts_log "32"
|
593
|
+
ibm_parse_column_attributes_args('bigint',*args)
|
594
|
+
return self
|
595
|
+
end
|
596
|
+
|
597
|
+
#Method to support the new syntax of rails 2.0 migrations (short-hand definitions) for columns of type char [character]
|
598
|
+
def char(*args)
|
599
|
+
puts_log "33"
|
600
|
+
ibm_parse_column_attributes_args('char',*args)
|
601
|
+
return self
|
602
|
+
end
|
603
|
+
alias_method :character, :char
|
604
|
+
|
605
|
+
# Overrides the abstract adapter in order to handle
|
606
|
+
# the DEFAULT option for the native XML datatype
|
607
|
+
def column(name, type, index: nil, **options)
|
608
|
+
puts_log "34 column"
|
609
|
+
name = name.to_s
|
610
|
+
type = type.to_sym if type
|
611
|
+
|
612
|
+
if @columns_hash[name]
|
613
|
+
if @columns_hash[name].primary_key?
|
614
|
+
raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
|
615
|
+
else
|
616
|
+
raise ArgumentError, "you can't define an already defined column '#{name}'."
|
617
|
+
end
|
618
|
+
end
|
659
619
|
|
660
|
-
|
661
|
-
|
662
|
-
def column(name, type, options ={})
|
663
|
-
# construct a column definition where @base is adaptor instance
|
664
|
-
column = ColumnDefinition.new(name, type)
|
620
|
+
# construct a column definition where @base is adaptor instance
|
621
|
+
column = new_column_definition(name, type, **options)
|
665
622
|
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
end
|
681
|
-
return sql
|
623
|
+
# DB2 does not accept DEFAULT NULL option for XML
|
624
|
+
# for table create, but does accept nullable option
|
625
|
+
unless type.to_s == 'xml'
|
626
|
+
column.null = options[:null]
|
627
|
+
column.default = options[:default]
|
628
|
+
else
|
629
|
+
column.null = options[:null]
|
630
|
+
# Override column object's (instance of ColumnDefinition structure)
|
631
|
+
# to_s which is expected to return the create_table SQL fragment
|
632
|
+
# and bypass DEFAULT NULL option while still appending NOT NULL
|
633
|
+
def column.to_s
|
634
|
+
sql = "#{base.quote_column_name(name)} #{type}"
|
635
|
+
unless self.null == nil
|
636
|
+
sql << " NOT NULL" if (self.null == false)
|
682
637
|
end
|
638
|
+
return sql
|
683
639
|
end
|
640
|
+
end
|
684
641
|
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
642
|
+
column.scale = options[:scale] if options[:scale]
|
643
|
+
column.precision = options[:precision] if options[:precision]
|
644
|
+
# append column's limit option and yield native limits
|
645
|
+
if options[:limit]
|
646
|
+
column.limit = options[:limit]
|
647
|
+
elsif @base.native_database_types[type.to_sym]
|
648
|
+
column.limit = @base.native_database_types[type.to_sym][:limit] if @base.native_database_types[type.to_sym].has_key? :limit
|
649
|
+
end
|
693
650
|
|
694
|
-
|
695
|
-
|
696
|
-
|
651
|
+
unless @columns.nil? or @columns.include? column
|
652
|
+
@columns << column
|
653
|
+
end
|
697
654
|
|
698
|
-
|
655
|
+
@columns_hash[name] = column
|
699
656
|
|
700
|
-
|
701
|
-
end
|
657
|
+
return self
|
702
658
|
end
|
703
|
-
|
659
|
+
end #end of class TableDefinition
|
660
|
+
end #end of module ColumnMethods
|
704
661
|
|
705
662
|
# The IBM_DB Adapter requires the native Ruby driver (ibm_db)
|
706
663
|
# for IBM data servers (ibm_db.so).
|
@@ -743,24 +700,36 @@ module ActiveRecord
|
|
743
700
|
'IBM_DB'
|
744
701
|
end
|
745
702
|
|
746
|
-
class
|
747
|
-
|
703
|
+
class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
|
704
|
+
private
|
705
|
+
def dealloc(stmt)
|
706
|
+
#stmt.close unless stmt.closed?
|
707
|
+
end
|
708
|
+
end
|
709
|
+
|
710
|
+
def build_statement_pool
|
711
|
+
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
748
712
|
end
|
749
713
|
|
750
714
|
def initialize(connection, ar3, logger, config, conn_options)
|
751
715
|
# Caching database connection configuration (+connect+ or +reconnect+ support)\
|
752
|
-
|
716
|
+
@config = config
|
753
717
|
@connection = connection
|
754
718
|
@isAr3 = ar3
|
755
719
|
@conn_options = conn_options
|
756
720
|
@database = config[:database]
|
757
721
|
@username = config[:username]
|
758
722
|
@password = config[:password]
|
723
|
+
@debug = config[:debug]
|
759
724
|
if config.has_key?(:host)
|
760
725
|
@host = config[:host]
|
761
726
|
@port = config[:port] || 50000 # default port
|
762
727
|
end
|
763
|
-
|
728
|
+
if config.has_key?(:schema)
|
729
|
+
@schema = config[:schema]
|
730
|
+
else
|
731
|
+
@schema = config[:username]
|
732
|
+
end
|
764
733
|
@security = config[:security] || nil
|
765
734
|
@authentication = config[:authentication] || nil
|
766
735
|
@timeout = config[:timeout] || 0 # default timeout value is 0
|
@@ -800,7 +769,7 @@ module ActiveRecord
|
|
800
769
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
801
770
|
when /10/
|
802
771
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
803
|
-
|
772
|
+
when /11/
|
804
773
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
805
774
|
when /12/
|
806
775
|
@servertype = IBM_DB2_ZOS.new(self, @isAr3)
|
@@ -818,6 +787,7 @@ module ActiveRecord
|
|
818
787
|
warn "Forcing servertype to LUW: DBMS name could not be retrieved. Check if your client version is of the right level"
|
819
788
|
@servertype = IBM_DB2_LUW.new(self, @isAr3)
|
820
789
|
end
|
790
|
+
@database_version = server_info.DBMS_VER
|
821
791
|
else
|
822
792
|
error_msg = IBM_DB.getErrormsg( @connection, IBM_DB::DB_CONN )
|
823
793
|
IBM_DB.close( @connection )
|
@@ -857,8 +827,23 @@ module ActiveRecord
|
|
857
827
|
end
|
858
828
|
end
|
859
829
|
|
830
|
+
def get_database_version
|
831
|
+
@database_version
|
832
|
+
end
|
833
|
+
|
834
|
+
def prepared_statements?
|
835
|
+
puts_log "prepared_statements?"
|
836
|
+
@prepared_statements && !prepared_statements_disabled_cache.include?(object_id)
|
837
|
+
end
|
838
|
+
alias :prepared_statements :prepared_statements?
|
839
|
+
|
840
|
+
def bind_params_length
|
841
|
+
999
|
842
|
+
end
|
843
|
+
|
860
844
|
# Optional connection attribute: database name space qualifier
|
861
845
|
def schema=(name)
|
846
|
+
puts_log "schema="
|
862
847
|
unless name == @schema
|
863
848
|
@schema = name
|
864
849
|
@servertype.set_schema(@schema)
|
@@ -867,6 +852,7 @@ module ActiveRecord
|
|
867
852
|
|
868
853
|
# Optional connection attribute: authenticated application user
|
869
854
|
def app_user=(name)
|
855
|
+
puts_log "app_user="
|
870
856
|
unless name == @app_user
|
871
857
|
option = {IBM_DB::SQL_ATTR_INFO_USERID => "#{name}"}
|
872
858
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -877,6 +863,7 @@ module ActiveRecord
|
|
877
863
|
|
878
864
|
# Optional connection attribute: OS account (client workstation)
|
879
865
|
def account=(name)
|
866
|
+
puts_log "account="
|
880
867
|
unless name == @account
|
881
868
|
option = {IBM_DB::SQL_ATTR_INFO_ACCTSTR => "#{name}"}
|
882
869
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -887,6 +874,7 @@ module ActiveRecord
|
|
887
874
|
|
888
875
|
# Optional connection attribute: application name
|
889
876
|
def application=(name)
|
877
|
+
puts_log "application="
|
890
878
|
unless name == @application
|
891
879
|
option = {IBM_DB::SQL_ATTR_INFO_APPLNAME => "#{name}"}
|
892
880
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -897,6 +885,7 @@ module ActiveRecord
|
|
897
885
|
|
898
886
|
# Optional connection attribute: client workstation name
|
899
887
|
def workstation=(name)
|
888
|
+
puts_log "workstation="
|
900
889
|
unless name == @workstation
|
901
890
|
option = {IBM_DB::SQL_ATTR_INFO_WRKSTNNAME => "#{name}"}
|
902
891
|
if IBM_DB.set_option( @connection, option, 1 )
|
@@ -906,61 +895,101 @@ module ActiveRecord
|
|
906
895
|
end
|
907
896
|
|
908
897
|
def self.visitor_for(pool)
|
898
|
+
puts_log "visitor_for"
|
909
899
|
Arel::Visitors::IBM_DB.new(pool)
|
910
900
|
end
|
911
901
|
|
912
|
-
|
902
|
+
#Check Arel version
|
913
903
|
begin
|
914
904
|
@arelVersion = Arel::VERSION.to_i
|
915
905
|
rescue
|
916
906
|
@arelVersion = 0
|
917
907
|
end
|
918
908
|
if(@arelVersion < 6 )
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
end
|
924
|
-
else
|
925
|
-
arel
|
909
|
+
def to_sql(arel, binds = [])
|
910
|
+
if arel.respond_to?(:ast)
|
911
|
+
visitor.accept(arel.ast) do
|
912
|
+
quote(*binds.shift.reverse)
|
926
913
|
end
|
914
|
+
else
|
915
|
+
arel
|
927
916
|
end
|
928
|
-
|
917
|
+
end
|
918
|
+
end
|
919
|
+
|
929
920
|
# This adapter supports migrations.
|
930
921
|
# Current limitations:
|
931
922
|
# +rename_column+ is not currently supported by the IBM data servers
|
932
923
|
# +remove_column+ is not currently supported by the DB2 for zOS data server
|
933
924
|
# Tables containing columns of XML data type do not support +remove_column+
|
934
925
|
def supports_migrations?
|
926
|
+
puts_log "supports_migrations?"
|
935
927
|
true
|
936
928
|
end
|
937
929
|
|
938
930
|
def supports_foreign_keys?
|
931
|
+
puts_log "supports_foreign_keys?"
|
939
932
|
true
|
940
933
|
end
|
941
934
|
|
942
935
|
def supports_datetime_with_precision?
|
943
|
-
|
936
|
+
puts_log "supports_datetime_with_precision?"
|
937
|
+
true
|
944
938
|
end
|
945
939
|
|
946
940
|
# This Adapter supports DDL transactions.
|
947
941
|
# This means CREATE TABLE and other DDL statements can be carried out as a transaction.
|
948
942
|
# That is the statements executed can be ROLLED BACK in case of any error during the process.
|
949
943
|
def supports_ddl_transactions?
|
944
|
+
puts_log "supports_ddl_transactions?"
|
945
|
+
true
|
946
|
+
end
|
947
|
+
|
948
|
+
def supports_explain?
|
949
|
+
puts_log "supports_explain?"
|
950
|
+
true
|
951
|
+
end
|
952
|
+
|
953
|
+
def supports_lazy_transactions?
|
954
|
+
puts_log "supports_lazy_transactions?"
|
955
|
+
true
|
956
|
+
end
|
957
|
+
|
958
|
+
def supports_comments?
|
959
|
+
true
|
960
|
+
end
|
961
|
+
|
962
|
+
def supports_views?
|
950
963
|
true
|
951
964
|
end
|
952
965
|
|
953
966
|
def log_query(sql, name) #:nodoc:
|
967
|
+
puts_log "log_query"
|
954
968
|
# Used by handle_lobs
|
955
969
|
log(sql,name){}
|
956
970
|
end
|
957
971
|
|
972
|
+
def supports_partitioned_indexes?
|
973
|
+
true
|
974
|
+
end
|
975
|
+
|
976
|
+
def puts_log (val)
|
977
|
+
begin
|
978
|
+
# puts val
|
979
|
+
rescue
|
980
|
+
end
|
981
|
+
if @debug == true
|
982
|
+
log(" IBM_DB = #{val}", "TRANSACTION"){}
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
958
986
|
#==============================================
|
959
987
|
# CONNECTION MANAGEMENT
|
960
988
|
#==============================================
|
961
989
|
|
962
990
|
# Tests the connection status
|
963
991
|
def active?
|
992
|
+
puts_log "active?"
|
964
993
|
IBM_DB.active @connection
|
965
994
|
rescue
|
966
995
|
false
|
@@ -969,6 +998,7 @@ module ActiveRecord
|
|
969
998
|
# Private method used by +reconnect!+.
|
970
999
|
# It connects to the database with the initially provided credentials
|
971
1000
|
def connect
|
1001
|
+
puts_log "connect"
|
972
1002
|
# If the type of connection is net based
|
973
1003
|
if(@username.nil? || @password.nil?)
|
974
1004
|
raise ArgumentError, "Username/Password cannot be nil"
|
@@ -1006,6 +1036,7 @@ module ActiveRecord
|
|
1006
1036
|
|
1007
1037
|
# Closes the current connection and opens a new one
|
1008
1038
|
def reconnect!
|
1039
|
+
puts_log "reconnect!"
|
1009
1040
|
disconnect!
|
1010
1041
|
connect
|
1011
1042
|
end
|
@@ -1016,100 +1047,50 @@ module ActiveRecord
|
|
1016
1047
|
# * true if succesfull
|
1017
1048
|
# * false if the connection is already closed
|
1018
1049
|
# * nil if an error is raised
|
1050
|
+
puts_log "disconnect!"
|
1019
1051
|
return nil if @connection.nil? || @connection == false
|
1020
1052
|
IBM_DB.close(@connection) rescue nil
|
1053
|
+
@connection = nil
|
1054
|
+
reset_transaction
|
1021
1055
|
end
|
1022
1056
|
|
1023
1057
|
#==============================================
|
1024
1058
|
# DATABASE STATEMENTS
|
1025
1059
|
#==============================================
|
1026
1060
|
|
1027
|
-
def create_table(name,
|
1061
|
+
def create_table(name, id: :primary_key, primary_key: nil, force: nil, **options)
|
1062
|
+
puts_log "create_table name=#{name}, id=#{id}, primary_key=#{primary_key}, force=#{force}"
|
1063
|
+
puts_log "create_table Options = #{options}"
|
1064
|
+
puts_log "primary_key_prefix_type = #{ActiveRecord::Base.primary_key_prefix_type}"
|
1065
|
+
puts_log caller
|
1028
1066
|
@servertype.setup_for_lob_table
|
1029
1067
|
#Table definition is complete only when a unique index is created on the primarykey column for DB2 V8 on zOS
|
1030
1068
|
|
1031
1069
|
#create index on id column if options[:id] is nil or id ==true
|
1032
1070
|
#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
|
-
|
1071
|
+
if !id.nil? || !primary_key.nil?
|
1072
|
+
if (!id.nil? && id == true)
|
1073
|
+
@servertype.create_index_after_table(name,"id")
|
1074
|
+
elsif !primary_key.nil?
|
1075
|
+
@servertype.create_index_after_table(name,primary_key.to_s)
|
1038
1076
|
end
|
1039
1077
|
else
|
1040
|
-
|
1078
|
+
@servertype.create_index_after_table(name,"id")
|
1041
1079
|
end
|
1042
|
-
super(name, options)
|
1043
|
-
end
|
1044
1080
|
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
results = []
|
1052
|
-
# Invokes the method +prepare+ in order prepare the SQL
|
1053
|
-
# IBM_DB.Statement is returned from which the statement is executed and results fetched
|
1054
|
-
pstmt = prepare(sql_param_hash["sqlSegment"], name)
|
1055
|
-
if(execute_prepared_stmt(pstmt, sql_param_hash["paramArray"]))
|
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
|
1081
|
+
#Just incase if id holds any other data type other than primary_key we override it,
|
1082
|
+
#otherwise it misses "GENERATED BY DEFAULT AS IDENTITY (START WITH 1000)"
|
1083
|
+
if !id.nil? && id != false && primary_key.nil? && ActiveRecord::Base.primary_key_prefix_type.nil?
|
1084
|
+
primary_key = :id
|
1085
|
+
options[:auto_increment] = true if options[:auto_increment].nil? and (id == :integer or id == :bigint)
|
1071
1086
|
end
|
1072
|
-
# The array of record hashes is returned
|
1073
|
-
results
|
1074
|
-
end
|
1075
1087
|
|
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
|
1088
|
+
super(name, id: id, primary_key: primary_key, force: force, **options)
|
1109
1089
|
end
|
1110
1090
|
|
1111
1091
|
#Calls the servertype select method to fetch the data
|
1112
1092
|
def fetch_data(stmt)
|
1093
|
+
puts_log "fetch_data"
|
1113
1094
|
if(stmt)
|
1114
1095
|
begin
|
1115
1096
|
return @servertype.select(stmt)
|
@@ -1118,33 +1099,41 @@ module ActiveRecord
|
|
1118
1099
|
if error_msg && !error_msg.empty?
|
1119
1100
|
raise StatementInvalid,"Failed to retrieve data: #{error_msg}"
|
1120
1101
|
else
|
1121
|
-
error_msg = "An unexpected error occurred during data retrieval"
|
1122
1102
|
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
1123
1103
|
raise error_msg
|
1124
1104
|
end
|
1125
1105
|
ensure
|
1126
1106
|
# Ensures to free the resources associated with the statement
|
1127
|
-
|
1107
|
+
if stmt
|
1108
|
+
puts_log "Free Statement #{stmt}"
|
1109
|
+
IBM_DB.free_stmt(stmt)
|
1110
|
+
end
|
1128
1111
|
end
|
1129
1112
|
end
|
1130
1113
|
end
|
1131
1114
|
|
1132
1115
|
def select(sql, name = nil, binds = [])
|
1116
|
+
puts_log "select #{sql}"
|
1133
1117
|
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"
|
1134
|
-
|
1118
|
+
begin
|
1119
|
+
sql.gsub( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
|
1120
|
+
rescue
|
1121
|
+
# ...
|
1122
|
+
end
|
1135
1123
|
|
1136
1124
|
results = []
|
1137
1125
|
|
1138
1126
|
if(binds.nil? || binds.empty?)
|
1139
1127
|
stmt = execute(sql, name)
|
1140
1128
|
else
|
1141
|
-
stmt =
|
1129
|
+
stmt = exec_query_ret_stmt(sql, name, binds, prepare = false)
|
1142
1130
|
end
|
1143
1131
|
|
1144
1132
|
cols = IBM_DB.resultCols(stmt)
|
1145
1133
|
|
1146
1134
|
if( stmt )
|
1147
1135
|
results = fetch_data(stmt)
|
1136
|
+
puts_log "Results = #{results}"
|
1148
1137
|
end
|
1149
1138
|
|
1150
1139
|
if(@isAr3)
|
@@ -1154,57 +1143,96 @@ module ActiveRecord
|
|
1154
1143
|
end
|
1155
1144
|
end
|
1156
1145
|
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1146
|
+
def translate_exception(exception, message:, sql:, binds:)
|
1147
|
+
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/
|
1148
|
+
error_msg2 = /SQL0204N .* is an undefined name/
|
1149
|
+
error_msg3 = /SQL0413N Overflow occurred during numeric data type conversion/
|
1150
|
+
error_msg4 = /SQL0407N Assignment of a NULL value to a NOT NULL column .* is not allowed/
|
1151
|
+
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/
|
1152
|
+
error_msg6 = /SQL0532N A parent row cannot be deleted because the relationship .* restricts the deletion/
|
1153
|
+
error_msg7 = /SQL0433N Value .* is too long/
|
1154
|
+
error_msg8 = /CLI0109E String data right truncation/
|
1155
|
+
if !error_msg1.match(message).nil?
|
1156
|
+
RecordNotUnique.new(message, sql: sql, binds: binds)
|
1157
|
+
elsif !error_msg2.match(message).nil?
|
1158
|
+
ArgumentError.new(message)
|
1159
|
+
elsif !error_msg3.match(message).nil?
|
1160
|
+
RangeError.new(message, sql: sql, binds: binds)
|
1161
|
+
elsif !error_msg4.match(message).nil?
|
1162
|
+
NotNullViolation.new(message, sql: sql, binds: binds)
|
1163
|
+
elsif !error_msg5.match(message).nil? or !error_msg6.match(message).nil?
|
1164
|
+
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
1165
|
+
elsif !error_msg7.match(message).nil? or !error_msg8.match(message).nil?
|
1166
|
+
ValueTooLong.new(message, sql: sql, binds: binds)
|
1167
|
+
elsif exception.message.match?(/called on a closed database/i)
|
1168
|
+
ConnectionNotEstablished.new(exception)
|
1169
|
+
else
|
1170
|
+
super
|
1172
1171
|
end
|
1172
|
+
end
|
1173
1173
|
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1174
|
+
def build_truncate_statement(table_name)
|
1175
|
+
puts_log "build_truncate_statement"
|
1176
|
+
"DELETE FROM #{quote_table_name(table_name)}"
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
def build_fixture_statements(fixture_set)
|
1180
|
+
fixture_set.flat_map do |table_name, fixtures|
|
1181
|
+
next if fixtures.empty?
|
1182
|
+
fixtures.map { |fixture| build_fixture_sql([fixture], table_name) }
|
1183
|
+
end.compact
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
def build_fixture_sql(fixtures, table_name)
|
1187
|
+
puts_log "build_fixture_sql"
|
1188
|
+
columns = schema_cache.columns_hash(table_name)
|
1189
|
+
|
1190
|
+
values_list = fixtures.map do |fixture|
|
1191
|
+
fixture = fixture.stringify_keys
|
1192
|
+
fixture = fixture.transform_keys(&:downcase)
|
1193
|
+
|
1194
|
+
unknown_columns = fixture.keys - columns.keys
|
1195
|
+
if unknown_columns.any?
|
1196
|
+
raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
|
1197
|
+
end
|
1198
|
+
|
1199
|
+
columns.map do |name, column|
|
1200
|
+
if fixture.key?(name)
|
1201
|
+
type = lookup_cast_type_from_column(column)
|
1202
|
+
with_yaml_fallback(type.serialize(fixture[name]))
|
1182
1203
|
else
|
1183
|
-
|
1184
|
-
error_msg = error_msg + ": #{fetch_error.message}" if !fetch_error.message.empty?
|
1185
|
-
raise error_msg
|
1204
|
+
default_insert_value(column)
|
1186
1205
|
end
|
1187
|
-
ensure
|
1188
|
-
# Ensures to free the resources associated with the statement
|
1189
|
-
IBM_DB.free_stmt(stmt) if stmt
|
1190
1206
|
end
|
1191
1207
|
end
|
1192
|
-
# The array of record hashes is returned
|
1193
|
-
results
|
1194
|
-
end
|
1195
1208
|
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1209
|
+
table = Arel::Table.new(table_name)
|
1210
|
+
manager = Arel::InsertManager.new
|
1211
|
+
manager.into(table)
|
1212
|
+
|
1213
|
+
if values_list.size == 1
|
1214
|
+
values = values_list.shift
|
1215
|
+
new_values = []
|
1216
|
+
columns.each_key.with_index { |column, i|
|
1217
|
+
unless values[i].equal?(DEFAULT_INSERT_VALUE)
|
1218
|
+
new_values << values[i]
|
1219
|
+
manager.columns << table[column]
|
1220
|
+
end
|
1221
|
+
}
|
1222
|
+
values_list << new_values
|
1223
|
+
else
|
1224
|
+
columns.each_key { |column| manager.columns << table[column] }
|
1225
|
+
end
|
1226
|
+
|
1227
|
+
manager.values = manager.create_values_list(values_list)
|
1228
|
+
visitor.compile(manager.ast)
|
1229
|
+
end
|
1203
1230
|
|
1204
1231
|
#inserts values from fixtures
|
1205
1232
|
#overridden to handle LOB's fixture insertion, as, in normal inserts callbacks are triggered but during fixture insertion callbacks are not triggered
|
1206
1233
|
#hence only markers like @@@IBMBINARY@@@ will be inserted and are not updated to actual data
|
1207
1234
|
def insert_fixture(fixture, table_name)
|
1235
|
+
puts_log "insert_fixture = #{fixture}"
|
1208
1236
|
if(fixture.respond_to?(:keys))
|
1209
1237
|
insert_query = "INSERT INTO #{quote_table_name(table_name)} ( #{fixture.keys.join(', ')})"
|
1210
1238
|
else
|
@@ -1253,7 +1281,6 @@ module ActiveRecord
|
|
1253
1281
|
end
|
1254
1282
|
end
|
1255
1283
|
|
1256
|
-
#log_query(insert_query,'fixture insert')
|
1257
1284
|
log(insert_query,'fixture insert') do
|
1258
1285
|
unless IBM_DB.execute(stmt, insert_values)
|
1259
1286
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
@@ -1266,19 +1293,24 @@ module ActiveRecord
|
|
1266
1293
|
end
|
1267
1294
|
|
1268
1295
|
def empty_insert_statement_value(pkey)
|
1269
|
-
|
1296
|
+
if !pkey.nil?
|
1297
|
+
"(#{pkey}) VALUES (DEFAULT)"
|
1298
|
+
else
|
1299
|
+
raise ArgumentError, "Empty Insert Statement not allowed in DB2"
|
1300
|
+
end
|
1270
1301
|
end
|
1271
1302
|
|
1272
1303
|
# Perform an insert and returns the last ID generated.
|
1273
1304
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
1274
1305
|
# and retrieved by the +last_generated_id+ method.
|
1275
1306
|
def insert_direct(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
1307
|
+
puts_log "insert_direct"
|
1276
1308
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1277
1309
|
@sql = []
|
1278
1310
|
@handle_lobs_triggered = false
|
1279
1311
|
end
|
1280
1312
|
|
1281
|
-
|
1313
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1282
1314
|
|
1283
1315
|
if stmt = execute(sql, name)
|
1284
1316
|
begin
|
@@ -1292,20 +1324,23 @@ module ActiveRecord
|
|
1292
1324
|
end
|
1293
1325
|
|
1294
1326
|
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds=[])
|
1327
|
+
puts_log "insert Binds = #{binds}"
|
1295
1328
|
if(@arelVersion < 6)
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1329
|
+
sql, binds = [to_sql(arel), binds]
|
1330
|
+
else
|
1331
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
1332
|
+
end
|
1300
1333
|
|
1334
|
+
puts_log "Binds 2 = #{binds}"
|
1335
|
+
puts_log "SQL = #{sql}"
|
1301
1336
|
#unless IBM_DBAdapter.respond_to?(:exec_insert)
|
1302
1337
|
if binds.nil? || binds.empty?
|
1303
1338
|
return insert_direct(sql, name, pk, id_value, sequence_name)
|
1304
1339
|
end
|
1305
1340
|
|
1306
|
-
|
1341
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1307
1342
|
|
1308
|
-
if stmt =
|
1343
|
+
if stmt = exec_insert_db2(sql, name, binds)
|
1309
1344
|
begin
|
1310
1345
|
@sql << sql
|
1311
1346
|
return id_value || @servertype.last_generated_id(stmt)
|
@@ -1315,18 +1350,36 @@ module ActiveRecord
|
|
1315
1350
|
end
|
1316
1351
|
end
|
1317
1352
|
|
1353
|
+
def exec_insert_db2(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
1354
|
+
puts_log "exec_insert_db2"
|
1355
|
+
sql, binds = sql_for_insert(sql, pk, binds)
|
1356
|
+
exec_query_ret_stmt(sql, name, binds, prepare = false)
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
def last_inserted_id(result)
|
1360
|
+
puts_log "last_inserted_id"
|
1361
|
+
return result
|
1362
|
+
end
|
1363
|
+
|
1364
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil) # :nodoc:
|
1365
|
+
puts_log "exec_insert"
|
1366
|
+
value = insert(sql)
|
1367
|
+
return value
|
1368
|
+
end
|
1369
|
+
|
1318
1370
|
# Praveen
|
1319
1371
|
# Performs an insert using the prepared statement and returns the last ID generated.
|
1320
1372
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
1321
1373
|
# and retrieved by the +last_generated_id+ method.
|
1322
1374
|
def prepared_insert(pstmt, param_array = nil, id_value = nil)
|
1375
|
+
puts_log "prepared_insert"
|
1323
1376
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1324
1377
|
@sql = []
|
1325
1378
|
@sql_parameter_values = []
|
1326
1379
|
@handle_lobs_triggered = false
|
1327
1380
|
end
|
1328
1381
|
|
1329
|
-
|
1382
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1330
1383
|
|
1331
1384
|
begin
|
1332
1385
|
if execute_prepared_stmt(pstmt, param_array)
|
@@ -1345,6 +1398,7 @@ module ActiveRecord
|
|
1345
1398
|
# Prepares and logs +sql+ commands and
|
1346
1399
|
# returns a +IBM_DB.Statement+ object.
|
1347
1400
|
def prepare(sql,name = nil)
|
1401
|
+
puts_log "prepare"
|
1348
1402
|
# The +log+ method is defined in the parent class +AbstractAdapter+
|
1349
1403
|
@prepared_sql = sql
|
1350
1404
|
log(sql,name) do
|
@@ -1356,17 +1410,15 @@ module ActiveRecord
|
|
1356
1410
|
#Executes the prepared statement
|
1357
1411
|
#ReturnsTrue on success and False on Failure
|
1358
1412
|
def execute_prepared_stmt(pstmt, param_array = nil)
|
1413
|
+
puts_log "execute_prepared_stmt"
|
1414
|
+
puts_log "Param array = #{param_array}"
|
1359
1415
|
if !param_array.nil? && param_array.size < 1
|
1360
1416
|
param_array = nil
|
1361
1417
|
end
|
1362
1418
|
|
1363
1419
|
if( !IBM_DB.execute(pstmt, param_array) )
|
1364
1420
|
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
|
1421
|
+
puts_log "Error = #{error_msg}"
|
1370
1422
|
IBM_DB.free_stmt(pstmt) if pstmt
|
1371
1423
|
raise StatementInvalid, error_msg
|
1372
1424
|
else
|
@@ -1374,45 +1426,117 @@ module ActiveRecord
|
|
1374
1426
|
end
|
1375
1427
|
end
|
1376
1428
|
|
1429
|
+
READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
|
1430
|
+
:desc, :describe
|
1431
|
+
) # :nodoc:
|
1432
|
+
private_constant :READ_QUERY
|
1433
|
+
|
1434
|
+
def write_query?(sql) # :nodoc:
|
1435
|
+
!READ_QUERY.match?(sql)
|
1436
|
+
rescue ArgumentError # Invalid encoding
|
1437
|
+
!READ_QUERY.match?(sql.b)
|
1438
|
+
end
|
1439
|
+
|
1440
|
+
def explain(arel, binds = [])
|
1441
|
+
sql = "EXPLAIN ALL SET QUERYNO = 1 FOR #{to_sql(arel, binds)}"
|
1442
|
+
stmt = execute(sql, "EXPLAIN")
|
1443
|
+
result = select("select * from explain_statement where explain_level = 'P' and queryno = 1", "EXPLAIN")
|
1444
|
+
return result[0]["total_cost"].to_s
|
1445
|
+
# Ensures to free the resources associated with the statement
|
1446
|
+
ensure
|
1447
|
+
IBM_DB.free_stmt(stmt) if stmt
|
1448
|
+
end
|
1449
|
+
|
1377
1450
|
# Executes +sql+ statement in the context of this connection using
|
1378
1451
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
1379
1452
|
# the executed +sql+ statement.
|
1380
|
-
|
1453
|
+
# Here prepare argument is not used, by default this method creates prepared statment and execute.
|
1454
|
+
def exec_query_ret_stmt(sql, name = 'SQL', binds = [], prepare = false)
|
1455
|
+
puts_log "exec_query_ret_stmt"
|
1456
|
+
check_if_write_query(sql)
|
1457
|
+
materialize_transactions
|
1458
|
+
mark_transaction_written_if_write(sql)
|
1381
1459
|
begin
|
1382
|
-
|
1383
|
-
|
1460
|
+
puts_log "SQL = #{sql}"
|
1461
|
+
puts_log "Binds = #{binds}"
|
1462
|
+
param_array = type_casted_binds(binds)
|
1463
|
+
puts_log "Param array = #{param_array}"
|
1464
|
+
|
1465
|
+
stmt = @servertype.prepare(sql, name)
|
1466
|
+
if prepare
|
1467
|
+
@statements[sql] = stmt
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
puts_log "Statement = #{stmt}"
|
1471
|
+
log(sql, name, binds, param_array) do
|
1472
|
+
if( stmt )
|
1473
|
+
if(execute_prepared_stmt(stmt, param_array))
|
1474
|
+
return stmt
|
1475
|
+
end
|
1476
|
+
else
|
1477
|
+
return false
|
1478
|
+
end
|
1384
1479
|
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
1480
|
ensure
|
1396
1481
|
@offset = @limit = nil
|
1397
1482
|
end
|
1398
1483
|
end
|
1399
1484
|
|
1485
|
+
def exec_query(sql, name = 'SQL', binds = [], prepare = false)
|
1486
|
+
select_prepared(sql, name, binds, prepare)
|
1487
|
+
end
|
1488
|
+
|
1489
|
+
def select_prepared(sql, name = nil, binds = [], prepare = true)
|
1490
|
+
puts_log "select_prepared"
|
1491
|
+
puts_log "select_prepared sql before = #{sql}"
|
1492
|
+
puts_log "select_prepared Binds = #{binds}"
|
1493
|
+
stmt = exec_query_ret_stmt(sql, name, binds, prepare)
|
1494
|
+
if !/^select .*/i.match(sql).nil?
|
1495
|
+
cols = IBM_DB.resultCols(stmt)
|
1496
|
+
|
1497
|
+
if( stmt )
|
1498
|
+
results = fetch_data(stmt)
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
puts_log "select_prepared columns = #{cols}"
|
1502
|
+
puts_log "select_prepared sql after = #{sql}"
|
1503
|
+
puts_log "select_prepared result = #{results}"
|
1504
|
+
else
|
1505
|
+
cols = nil
|
1506
|
+
result = nil
|
1507
|
+
end
|
1508
|
+
if(@isAr3)
|
1509
|
+
return results
|
1510
|
+
else
|
1511
|
+
return ActiveRecord::Result.new(cols, results)
|
1512
|
+
end
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
def check_if_write_query(sql) #For rails 7.1 just remove this function as it will be defined in AbstractAdapter class
|
1516
|
+
if preventing_writes? && write_query?(sql)
|
1517
|
+
raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
|
1518
|
+
end
|
1519
|
+
end
|
1520
|
+
|
1400
1521
|
# Executes and logs +sql+ commands and
|
1401
1522
|
# returns a +IBM_DB.Statement+ object.
|
1402
1523
|
def execute(sql, name=nil)
|
1403
1524
|
# Logs and execute the sql instructions.
|
1404
1525
|
# The +log+ method is defined in the parent class +AbstractAdapter+
|
1405
|
-
|
1526
|
+
#sql='INSERT INTO ar_internal_metadata (key, value, created_at, updated_at) VALUES ('10', '10', '10', '10')
|
1527
|
+
puts_log "execute"
|
1528
|
+
puts_log "#{sql}"
|
1529
|
+
check_if_write_query(sql)
|
1530
|
+
materialize_transactions
|
1531
|
+
mark_transaction_written_if_write(sql)
|
1406
1532
|
log(sql , name) do
|
1407
1533
|
@servertype.execute(sql, name)
|
1408
1534
|
end
|
1409
1535
|
end
|
1410
1536
|
|
1411
|
-
def exec_insert(sql,name,binds,pk,sequence_name)
|
1412
|
-
end
|
1413
|
-
|
1414
1537
|
# Executes an "UPDATE" SQL statement
|
1415
1538
|
def update_direct(sql, name = nil)
|
1539
|
+
puts_log "update_direct"
|
1416
1540
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1417
1541
|
@sql = []
|
1418
1542
|
@handle_lobs_triggered = false
|
@@ -1433,13 +1557,14 @@ module ActiveRecord
|
|
1433
1557
|
|
1434
1558
|
#Praveen
|
1435
1559
|
def prepared_update(pstmt, param_array = nil )
|
1560
|
+
puts_log "prepared_update"
|
1436
1561
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
1437
1562
|
@sql = []
|
1438
1563
|
@sql_parameter_values = []
|
1439
1564
|
@handle_lobs_triggered = false
|
1440
1565
|
end
|
1441
1566
|
|
1442
|
-
|
1567
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1443
1568
|
|
1444
1569
|
begin
|
1445
1570
|
if execute_prepared_stmt(pstmt, param_array)
|
@@ -1461,11 +1586,12 @@ module ActiveRecord
|
|
1461
1586
|
alias_method :prepared_delete, :prepared_update
|
1462
1587
|
|
1463
1588
|
def update(arel, name = nil, binds = [])
|
1589
|
+
puts_log "update"
|
1464
1590
|
if(@arelVersion < 6 )
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1591
|
+
sql = to_sql(arel)
|
1592
|
+
else
|
1593
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
1594
|
+
end
|
1469
1595
|
|
1470
1596
|
# Make sure the WHERE clause handles NULL's correctly
|
1471
1597
|
sqlarray = sql.split(/\s*WHERE\s*/)
|
@@ -1482,13 +1608,13 @@ module ActiveRecord
|
|
1482
1608
|
sql = sql + sqlarray[size-1]
|
1483
1609
|
end
|
1484
1610
|
|
1485
|
-
|
1611
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1486
1612
|
|
1487
1613
|
if binds.nil? || binds.empty?
|
1488
1614
|
update_direct(sql, name)
|
1489
1615
|
else
|
1490
1616
|
begin
|
1491
|
-
if stmt =
|
1617
|
+
if stmt = exec_query_ret_stmt(sql, name, binds, prepare = true)
|
1492
1618
|
IBM_DB.num_rows(stmt)
|
1493
1619
|
end
|
1494
1620
|
ensure
|
@@ -1501,14 +1627,18 @@ module ActiveRecord
|
|
1501
1627
|
|
1502
1628
|
# Begins the transaction (and turns off auto-committing)
|
1503
1629
|
def begin_db_transaction
|
1630
|
+
puts_log "begin_db_transaction"
|
1631
|
+
log("begin transaction", "TRANSACTION") {
|
1504
1632
|
# Turns off the auto-commit
|
1505
|
-
IBM_DB.autocommit(@connection, IBM_DB::SQL_AUTOCOMMIT_OFF)
|
1633
|
+
IBM_DB.autocommit(@connection, IBM_DB::SQL_AUTOCOMMIT_OFF) }
|
1506
1634
|
end
|
1507
1635
|
|
1508
1636
|
# Commits the transaction and turns on auto-committing
|
1509
1637
|
def commit_db_transaction
|
1638
|
+
puts_log "commit_db_transaction"
|
1639
|
+
log("commit transaction", "TRANSACTION") {
|
1510
1640
|
# Commits the transaction
|
1511
|
-
IBM_DB.commit @connection rescue nil
|
1641
|
+
IBM_DB.commit @connection rescue nil }
|
1512
1642
|
# Turns on auto-committing
|
1513
1643
|
IBM_DB.autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
|
1514
1644
|
end
|
@@ -1516,85 +1646,26 @@ module ActiveRecord
|
|
1516
1646
|
# Rolls back the transaction and turns on auto-committing. Must be
|
1517
1647
|
# done if the transaction block raises an exception or returns false
|
1518
1648
|
def rollback_db_transaction
|
1649
|
+
puts_log "rollback_db_transaction"
|
1650
|
+
log("rollback transaction", "TRANSACTION") {
|
1519
1651
|
# ROLLBACK the transaction
|
1520
|
-
IBM_DB.rollback(@connection) rescue nil
|
1652
|
+
IBM_DB.rollback(@connection) rescue nil }
|
1653
|
+
ActiveRecord::Base.clear_query_caches_for_current_thread
|
1521
1654
|
# Turns on auto-committing
|
1522
1655
|
IBM_DB.autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
|
1523
1656
|
end
|
1524
1657
|
|
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
1658
|
def default_sequence_name(table, column) # :nodoc:
|
1659
|
+
puts_log "72"
|
1577
1660
|
"#{table}_#{column}_seq"
|
1578
1661
|
end
|
1579
1662
|
|
1580
|
-
|
1581
1663
|
#==============================================
|
1582
1664
|
# QUOTING
|
1583
1665
|
#==============================================
|
1584
1666
|
|
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
1667
|
def quote_value_for_pstmt(value, column=nil)
|
1597
|
-
|
1668
|
+
puts_log "quote_value_for_pstmt"
|
1598
1669
|
return value.quoted_id if value.respond_to?(:quoted_id)
|
1599
1670
|
|
1600
1671
|
case value
|
@@ -1621,98 +1692,52 @@ module ActiveRecord
|
|
1621
1692
|
end
|
1622
1693
|
end
|
1623
1694
|
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
|
1695
|
+
|
1696
|
+
# Quotes a given string, escaping single quote (') characters.
|
1697
|
+
def quote_string(string)
|
1698
|
+
puts_log "quote_string"
|
1699
|
+
string.gsub(/'/, "''")
|
1700
|
+
#string.gsub('\\', '\&\&').gsub("'", "''")
|
1701
|
+
end
|
1700
1702
|
|
1701
1703
|
# *true* is represented by a smallint 1, *false*
|
1702
1704
|
# by 0, as no native boolean type exists in DB2.
|
1703
1705
|
# Numerics are not quoted in DB2.
|
1704
1706
|
def quoted_true
|
1705
|
-
"
|
1707
|
+
puts_log "quoted_true"
|
1708
|
+
"1".freeze
|
1706
1709
|
end
|
1707
1710
|
|
1708
1711
|
def quoted_false
|
1709
|
-
"
|
1712
|
+
puts_log "quoted_false"
|
1713
|
+
"0".freeze
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
def unquoted_true
|
1717
|
+
puts_log "unquoted_true"
|
1718
|
+
1
|
1719
|
+
end
|
1720
|
+
|
1721
|
+
def unquoted_false
|
1722
|
+
puts_log "unquoted_false"
|
1723
|
+
0
|
1724
|
+
end
|
1725
|
+
|
1726
|
+
def quote_table_name(name)
|
1727
|
+
puts_log "quote_table_name"
|
1728
|
+
name
|
1729
|
+
#@servertype.check_reserved_words(name).gsub('"', '').gsub("'",'')
|
1710
1730
|
end
|
1711
1731
|
|
1712
1732
|
def quote_column_name(name)
|
1713
|
-
|
1733
|
+
puts_log "quote_column_name"
|
1734
|
+
@servertype.check_reserved_words(name).gsub('"', '').gsub("'",'')
|
1714
1735
|
end
|
1715
1736
|
|
1737
|
+
def quoted_binary(value)
|
1738
|
+
puts_log "quoted_binary"
|
1739
|
+
"CAST(x'#{value.hex}' AS BLOB)"
|
1740
|
+
end
|
1716
1741
|
#==============================================
|
1717
1742
|
# SCHEMA STATEMENTS
|
1718
1743
|
#==============================================
|
@@ -1721,7 +1746,7 @@ module ActiveRecord
|
|
1721
1746
|
# database types
|
1722
1747
|
def native_database_types
|
1723
1748
|
{
|
1724
|
-
:primary_key => { :name => @servertype.primary_key_definition(@start_id)},
|
1749
|
+
:primary_key => { :name => @servertype.primary_key_definition(@start_id) },
|
1725
1750
|
:string => { :name => "varchar", :limit => 255 },
|
1726
1751
|
:text => { :name => "clob" },
|
1727
1752
|
:integer => { :name => "integer" },
|
@@ -1750,6 +1775,7 @@ module ActiveRecord
|
|
1750
1775
|
end
|
1751
1776
|
|
1752
1777
|
def build_conn_str_for_dbops()
|
1778
|
+
puts_log "build_conn_str_for_dbops"
|
1753
1779
|
connect_str = "DRIVER={IBM DB2 ODBC DRIVER};ATTACH=true;"
|
1754
1780
|
if(!@host.nil?)
|
1755
1781
|
connect_str << "HOSTNAME=#{@host};"
|
@@ -1761,6 +1787,7 @@ module ActiveRecord
|
|
1761
1787
|
end
|
1762
1788
|
|
1763
1789
|
def drop_database(dbName)
|
1790
|
+
puts_log "drop_database"
|
1764
1791
|
connect_str = build_conn_str_for_dbops()
|
1765
1792
|
|
1766
1793
|
#Ensure connection is closed before trying to drop a database.
|
@@ -1784,6 +1811,7 @@ module ActiveRecord
|
|
1784
1811
|
end
|
1785
1812
|
|
1786
1813
|
def create_database(dbName, codeSet=nil, mode=nil)
|
1814
|
+
puts_log "create_database"
|
1787
1815
|
connect_str = build_conn_str_for_dbops()
|
1788
1816
|
|
1789
1817
|
#Ensure connection is closed before trying to drop a database.
|
@@ -1805,18 +1833,41 @@ module ActiveRecord
|
|
1805
1833
|
raise "Could not create Database due to: #{error}"
|
1806
1834
|
end
|
1807
1835
|
end
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
1811
|
-
|
1812
|
-
def valid_type?(type)
|
1813
|
-
#!native_database_types[type].nil?
|
1814
|
-
native_database_types[type].nil?
|
1836
|
+
|
1837
|
+
def valid_type?(type)
|
1838
|
+
!native_database_types[type].nil?
|
1815
1839
|
end
|
1816
|
-
|
1840
|
+
|
1817
1841
|
# IBM data servers do not support limits on certain data types (unlike MySQL)
|
1818
1842
|
# Limit is supported for the {float, decimal, numeric, varchar, clob, blob, graphic, vargraphic} data types.
|
1819
1843
|
def type_to_sql(type, limit=nil, precision=nil, scale=nil )
|
1844
|
+
puts_log "type_to_sql"
|
1845
|
+
puts_log "Type = #{type}, Limit = #{limit}"
|
1846
|
+
|
1847
|
+
if type.to_sym == :binary and limit.class == Hash and limit.has_key?("limit".to_sym)
|
1848
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1849
|
+
sql_segment << "(#{limit[:limit]})"
|
1850
|
+
return sql_segment
|
1851
|
+
end
|
1852
|
+
|
1853
|
+
if type.to_sym == :datetime and limit.class == Hash and limit.has_key?("precision".to_sym)
|
1854
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1855
|
+
if limit[:precision].nil?
|
1856
|
+
return sql_segment
|
1857
|
+
elsif (0..12) === limit[:precision]
|
1858
|
+
sql_segment << "(#{limit[:precision]})"
|
1859
|
+
return sql_segment
|
1860
|
+
else
|
1861
|
+
raise ArgumentError, "No #{sql_segment} type has precision of #{limit[:precision]}. The allowed range of precision is from 0 to 12"
|
1862
|
+
end
|
1863
|
+
end
|
1864
|
+
|
1865
|
+
if type.to_sym == :string and limit.class == Hash and limit.has_key?("limit".to_sym)
|
1866
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1867
|
+
sql_segment << "(#{limit[:limit]})"
|
1868
|
+
return sql_segment
|
1869
|
+
end
|
1870
|
+
|
1820
1871
|
if type.to_sym == :decimal
|
1821
1872
|
if limit.class == Hash
|
1822
1873
|
if limit.has_key?("precision".to_sym)
|
@@ -1834,6 +1885,9 @@ module ActiveRecord
|
|
1834
1885
|
return sql_segment
|
1835
1886
|
elsif scale.nil? && !precision.nil?
|
1836
1887
|
sql_segment << "(#{precision})"
|
1888
|
+
return sql_segment
|
1889
|
+
elsif precision.nil? && !scale.nil?
|
1890
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
|
1837
1891
|
else
|
1838
1892
|
return sql_segment
|
1839
1893
|
end
|
@@ -1845,50 +1899,48 @@ module ActiveRecord
|
|
1845
1899
|
return sql_segment
|
1846
1900
|
end
|
1847
1901
|
|
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
|
1902
|
+
if type.to_sym == :vargraphic
|
1903
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1904
|
+
if limit.class == Hash
|
1905
|
+
if limit.has_key?("limit".to_sym)
|
1906
|
+
limit1 = limit[:limit]
|
1907
|
+
sql_segment << "(#{limit1})"
|
1908
|
+
else
|
1909
|
+
return "vargraphic(1)"
|
1910
|
+
end
|
1911
|
+
else
|
1912
|
+
if limit != nil
|
1913
|
+
sql_segment << "(#{limit})"
|
1914
|
+
else
|
1915
|
+
return "vargraphic(1)"
|
1916
|
+
end
|
1917
|
+
end
|
1918
|
+
return sql_segment
|
1884
1919
|
end
|
1885
1920
|
|
1886
|
-
|
1921
|
+
if type.to_sym == :graphic
|
1922
|
+
sql_segment = native_database_types[type.to_sym][:name].to_s
|
1923
|
+
if limit.class == Hash
|
1924
|
+
if limit.has_key?("limit".to_sym)
|
1925
|
+
limit1 = limit[:limit]
|
1926
|
+
sql_segment << "(#{limit1})"
|
1927
|
+
else
|
1928
|
+
return "graphic(1)"
|
1929
|
+
end
|
1930
|
+
else
|
1931
|
+
if limit != nil
|
1932
|
+
sql_segment << "(#{limit})"
|
1933
|
+
else
|
1934
|
+
return "graphic(1)"
|
1935
|
+
end
|
1936
|
+
end
|
1937
|
+
return sql_segment
|
1938
|
+
end
|
1887
1939
|
|
1888
1940
|
if limit.class == Hash
|
1889
|
-
return super if limit.has_key?("limit".to_sym).nil?
|
1941
|
+
return super(type) if limit.has_key?("limit".to_sym).nil?
|
1890
1942
|
else
|
1891
|
-
return super if limit.nil?
|
1943
|
+
return super(type) if limit.nil?
|
1892
1944
|
end
|
1893
1945
|
|
1894
1946
|
# strip off limits on data types not supporting them
|
@@ -1899,23 +1951,17 @@ module ActiveRecord
|
|
1899
1951
|
else
|
1900
1952
|
return super(type)
|
1901
1953
|
end
|
1902
|
-
|
1903
1954
|
end
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1955
|
+
|
1910
1956
|
# Returns the maximum length a table alias identifier can be.
|
1911
1957
|
# IBM data servers (cross-platform) table limit is 128 characters
|
1912
1958
|
def table_alias_length
|
1913
1959
|
128
|
1914
1960
|
end
|
1915
|
-
|
1916
1961
|
|
1917
1962
|
# Retrieves table's metadata for a specified shema name
|
1918
1963
|
def tables(name = nil)
|
1964
|
+
puts_log "tables"
|
1919
1965
|
# Initializes the tables array
|
1920
1966
|
tables = []
|
1921
1967
|
# Retrieve table's metadata through IBM_DB driver
|
@@ -1954,16 +2000,13 @@ module ActiveRecord
|
|
1954
2000
|
return tables
|
1955
2001
|
end
|
1956
2002
|
|
1957
|
-
###################################
|
1958
|
-
|
1959
|
-
|
1960
2003
|
# Retrieves views's metadata for a specified shema name
|
1961
2004
|
def views
|
2005
|
+
puts_log "views"
|
1962
2006
|
# Initializes the tables array
|
1963
2007
|
tables = []
|
1964
2008
|
# Retrieve view's metadata through IBM_DB driver
|
1965
|
-
stmt = IBM_DB.tables(@connection, nil,
|
1966
|
-
@servertype.set_case(@schema))
|
2009
|
+
stmt = IBM_DB.tables(@connection, nil, @servertype.set_case(@schema))
|
1967
2010
|
if(stmt)
|
1968
2011
|
begin
|
1969
2012
|
# Fetches all the records available
|
@@ -1996,18 +2039,19 @@ module ActiveRecord
|
|
1996
2039
|
# Returns the tables array
|
1997
2040
|
return tables
|
1998
2041
|
end
|
1999
|
-
|
2000
|
-
|
2042
|
+
|
2001
2043
|
# Returns the primary key of the mentioned table
|
2002
2044
|
def primary_key(table_name)
|
2003
|
-
|
2045
|
+
puts_log "primary_key"
|
2046
|
+
pk_name = []
|
2004
2047
|
stmt = IBM_DB.primary_keys( @connection, nil,
|
2005
2048
|
@servertype.set_case(@schema),
|
2006
|
-
@servertype.set_case(table_name))
|
2049
|
+
@servertype.set_case(table_name.to_s))
|
2007
2050
|
if(stmt)
|
2008
2051
|
begin
|
2009
|
-
|
2010
|
-
|
2052
|
+
while ( pk_index_row = IBM_DB.fetch_array(stmt) )
|
2053
|
+
puts_log "Primary_keys = #{pk_index_row}"
|
2054
|
+
pk_name << pk_index_row[3].downcase
|
2011
2055
|
end
|
2012
2056
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
2013
2057
|
error_msg = IBM_DB.getErrormsg( stmt, IBM_DB::DB_STMT )
|
@@ -2029,11 +2073,19 @@ module ActiveRecord
|
|
2029
2073
|
raise StandardError.new('An unexpected error occurred during primary key retrieval')
|
2030
2074
|
end
|
2031
2075
|
end
|
2032
|
-
|
2076
|
+
if pk_name.length() == 1
|
2077
|
+
return pk_name[0]
|
2078
|
+
elsif pk_name.empty?
|
2079
|
+
return nil
|
2080
|
+
else
|
2081
|
+
return pk_name
|
2082
|
+
end
|
2033
2083
|
end
|
2034
2084
|
|
2035
2085
|
# Returns an array of non-primary key indexes for a specified table name
|
2036
2086
|
def indexes(table_name, name = nil)
|
2087
|
+
puts_log "indexes"
|
2088
|
+
puts_log "Table = #{table_name}"
|
2037
2089
|
# to_s required because +table_name+ may be a symbol.
|
2038
2090
|
table_name = table_name.to_s
|
2039
2091
|
# Checks if a blank table name has been given.
|
@@ -2055,11 +2107,13 @@ module ActiveRecord
|
|
2055
2107
|
if(stmt)
|
2056
2108
|
begin
|
2057
2109
|
while ( pk_index_row = IBM_DB.fetch_array(stmt) )
|
2110
|
+
puts_log "Primary keys = #{pk_index_row}"
|
2111
|
+
puts_log "pk_index = #{pk_index}"
|
2058
2112
|
if pk_index_row[5]
|
2059
2113
|
pk_index_name = pk_index_row[5].downcase
|
2060
2114
|
pk_index_columns = [pk_index_row[3].downcase] # COLUMN_NAME
|
2061
2115
|
if pk_index
|
2062
|
-
pk_index.columns
|
2116
|
+
pk_index.columns << pk_index_columns
|
2063
2117
|
else
|
2064
2118
|
pk_index = IndexDefinition.new(table_name, pk_index_name, true, pk_index_columns)
|
2065
2119
|
end
|
@@ -2115,7 +2169,10 @@ module ActiveRecord
|
|
2115
2169
|
end
|
2116
2170
|
|
2117
2171
|
unless is_composite
|
2118
|
-
indexes
|
2172
|
+
sql = "select remarks from syscat.indexes where tabname = #{quote(table_name.upcase)} and indname = #{quote(index_stats[5])}"
|
2173
|
+
comment = single_value_from_rows(select_prepared(sql).rows)
|
2174
|
+
|
2175
|
+
indexes << IndexDefinition.new(table_name, index_name, index_unique, index_columns, comment: comment)
|
2119
2176
|
index_schema << index_qualifier
|
2120
2177
|
end
|
2121
2178
|
end
|
@@ -2143,6 +2200,7 @@ module ActiveRecord
|
|
2143
2200
|
|
2144
2201
|
# remove the primary key index entry.... should not be dumped by the dumper
|
2145
2202
|
|
2203
|
+
puts_log "Indexes 1 = #{pk_index}"
|
2146
2204
|
i = 0
|
2147
2205
|
indexes.each do |index|
|
2148
2206
|
if pk_index && index.columns == pk_index.columns
|
@@ -2151,12 +2209,13 @@ module ActiveRecord
|
|
2151
2209
|
i = i+1
|
2152
2210
|
end
|
2153
2211
|
# Returns the indexes array
|
2212
|
+
puts_log "Indexes 2 = #{indexes}"
|
2154
2213
|
return indexes
|
2155
2214
|
end
|
2156
2215
|
|
2157
|
-
|
2158
2216
|
# Mapping IBM data servers SQL datatypes to Ruby data types
|
2159
2217
|
def simplified_type2(field_type)
|
2218
|
+
puts_log "simplified_type2"
|
2160
2219
|
case field_type
|
2161
2220
|
# if +field_type+ contains 'for bit data' handle it as a binary
|
2162
2221
|
when /for bit data/i
|
@@ -2193,10 +2252,10 @@ module ActiveRecord
|
|
2193
2252
|
"rowid"
|
2194
2253
|
end
|
2195
2254
|
end # method simplified_type
|
2196
|
-
|
2197
|
-
|
2255
|
+
|
2198
2256
|
# Mapping IBM data servers SQL datatypes to Ruby data types
|
2199
2257
|
def simplified_type(field_type)
|
2258
|
+
puts_log "simplified_type"
|
2200
2259
|
case field_type
|
2201
2260
|
# if +field_type+ contains 'for bit data' handle it as a binary
|
2202
2261
|
when /for bit data/i
|
@@ -2210,7 +2269,7 @@ module ActiveRecord
|
|
2210
2269
|
when /float|double|real/i
|
2211
2270
|
:float
|
2212
2271
|
when /timestamp|datetime/i
|
2213
|
-
:
|
2272
|
+
:datetime
|
2214
2273
|
when /time/i
|
2215
2274
|
:time
|
2216
2275
|
when /date/i
|
@@ -2233,11 +2292,35 @@ module ActiveRecord
|
|
2233
2292
|
:rowid
|
2234
2293
|
end
|
2235
2294
|
end # method simplified_type
|
2236
|
-
|
2237
|
-
|
2295
|
+
|
2296
|
+
def extract_value_from_default(default)
|
2297
|
+
case default
|
2298
|
+
when /IDENTITY GENERATED BY DEFAULT/i
|
2299
|
+
nil
|
2300
|
+
when /^null$/i
|
2301
|
+
nil
|
2302
|
+
# Quoted types
|
2303
|
+
when /^'(.*)'$/m
|
2304
|
+
$1.gsub("''", "'")
|
2305
|
+
# Quoted types
|
2306
|
+
when /^"(.*)"$/m
|
2307
|
+
$1.gsub('""', '"')
|
2308
|
+
# Numeric types
|
2309
|
+
when /\A-?\d+(\.\d*)?\z/
|
2310
|
+
$&
|
2311
|
+
else
|
2312
|
+
# Anything else is blank or some function
|
2313
|
+
# and we can't know the value of that, so return nil.
|
2314
|
+
nil
|
2315
|
+
end
|
2316
|
+
end
|
2317
|
+
|
2238
2318
|
# Returns an array of Column objects for the table specified by +table_name+
|
2239
|
-
def columns(table_name)
|
2319
|
+
def columns(table_name)
|
2320
|
+
default_blob_length = 1048576
|
2240
2321
|
# to_s required because it may be a symbol.
|
2322
|
+
puts_log "columns"
|
2323
|
+
puts_log caller
|
2241
2324
|
table_name = @servertype.set_case(table_name.to_s)
|
2242
2325
|
|
2243
2326
|
# Checks if a blank table name has been given.
|
@@ -2249,74 +2332,94 @@ module ActiveRecord
|
|
2249
2332
|
stmt = IBM_DB.columns( @connection, nil,
|
2250
2333
|
@servertype.set_case(@schema),
|
2251
2334
|
@servertype.set_case(table_name) )
|
2335
|
+
# sql = "select * from sysibm.sqlcolumns where table_name = #{quote(table_name.upcase)}"
|
2336
|
+
if @debug == true
|
2337
|
+
sql = "select * from syscat.columns where tabname = #{quote(table_name.upcase)}"
|
2338
|
+
puts_log "SYSIBM.SQLCOLUMNS = #{select_prepared(sql).rows}"
|
2339
|
+
end
|
2340
|
+
|
2252
2341
|
if(stmt)
|
2253
2342
|
begin
|
2254
2343
|
# Fetches all the columns and assigns them to col.
|
2255
2344
|
# +col+ is an hash with keys/value pairs for a column
|
2256
2345
|
while col = IBM_DB.fetch_assoc(stmt)
|
2346
|
+
puts_log col
|
2257
2347
|
column_name = col["column_name"].downcase
|
2258
2348
|
# Assigns the column default value.
|
2259
2349
|
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?
|
2350
|
+
default_value = extract_value_from_default(column_default_value)
|
2266
2351
|
# Assigns the column type
|
2267
2352
|
column_type = col["type_name"].downcase
|
2353
|
+
|
2268
2354
|
# Assigns the field length (size) for the column
|
2269
2355
|
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2356
|
+
if column_type =~ /integer|bigint/i
|
2357
|
+
column_length = col["buffer_length"]
|
2358
|
+
else
|
2359
|
+
column_length = col["column_size"]
|
2360
|
+
end
|
2273
2361
|
column_scale = col["decimal_digits"]
|
2274
2362
|
# The initializer of the class Column, requires the +column_length+ to be declared
|
2275
2363
|
# between brackets after the datatype(e.g VARCHAR(50)) for :string and :text types.
|
2276
2364
|
# If it's a "for bit data" field it does a subsitution in place, if not
|
2277
2365
|
# 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
|
2366
|
+
if column_type.match(/decimal|numeric/)
|
2367
|
+
if column_length > 0 and column_scale > 0
|
2283
2368
|
column_type << "(#{column_length},#{column_scale})"
|
2284
|
-
elsif
|
2285
|
-
column_type << "" # override native limits incompatible with table create
|
2286
|
-
else
|
2369
|
+
elsif column_length > 0 and column_scale == 0
|
2287
2370
|
column_type << "(#{column_length})"
|
2288
2371
|
end
|
2372
|
+
elsif column_type.match(/timestamp/)
|
2373
|
+
column_type << "(#{column_scale})"
|
2374
|
+
elsif column_type.match(/varchar/) and column_length > 0
|
2375
|
+
column_type << "(#{column_length})"
|
2289
2376
|
end
|
2290
|
-
|
2377
|
+
|
2291
2378
|
column_nullable = (col["nullable"] == 1) ? true : false
|
2292
2379
|
# 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
|
-
# +column_name+, +default_value+, +column_type+ and +column_nullable+.
|
2296
|
-
#if(@arelVersion >= 6 )
|
2297
|
-
|
2298
|
-
#cast_type = lookup_cast_type(column_type)
|
2299
|
-
|
2300
|
-
ruby_type = simplified_type2(column_type)
|
2380
|
+
if !(column_name.match(/db2_generated_rowid_for_lobs/i))
|
2381
|
+
ruby_type = simplified_type(column_type)
|
2301
2382
|
precision = extract_precision(ruby_type)
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2305
|
-
|
2383
|
+
|
2384
|
+
if column_type.match(/timestamp|integer|bigint|date|time|blob/i)
|
2385
|
+
if column_type.match(/timestamp/i)
|
2386
|
+
precision = column_scale
|
2387
|
+
if !default_value.nil?
|
2388
|
+
default_value[10] = " "
|
2389
|
+
default_value[13] = ":"
|
2390
|
+
default_value[16] = ":"
|
2391
|
+
end
|
2392
|
+
elsif column_type.match(/time/i)
|
2393
|
+
if !default_value.nil?
|
2394
|
+
default_value[2] = ":"
|
2395
|
+
default_value[5] = ":"
|
2396
|
+
end
|
2397
|
+
end
|
2398
|
+
column_scale = nil
|
2399
|
+
if !(column_type.match(/blob/i) and column_length != default_blob_length) and !column_type.match(/bigint/i)
|
2400
|
+
column_length = nil
|
2401
|
+
end
|
2402
|
+
elsif column_type.match(/decimal|numeric/)
|
2403
|
+
precision = column_length
|
2404
|
+
column_length = nil
|
2405
|
+
end
|
2406
|
+
|
2407
|
+
if ruby_type.to_s == "boolean"
|
2408
|
+
column_type = "boolean"
|
2409
|
+
end
|
2410
|
+
|
2411
|
+
default_function = extract_default_function(default_value, column_default_value)
|
2412
|
+
|
2306
2413
|
sqltype_metadata = SqlTypeMetadata.new(
|
2307
2414
|
#sql_type: sql_type,
|
2308
|
-
sql_type:
|
2415
|
+
sql_type: column_type,
|
2309
2416
|
type: ruby_type,
|
2310
2417
|
limit: column_length,
|
2311
2418
|
precision: precision,
|
2312
2419
|
scale: column_scale,
|
2313
2420
|
)
|
2314
2421
|
|
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
|
2422
|
+
columns << Column.new(column_name, default_value, sqltype_metadata, column_nullable, default_function, comment: col["remarks"])
|
2320
2423
|
end
|
2321
2424
|
end
|
2322
2425
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
@@ -2340,10 +2443,20 @@ module ActiveRecord
|
|
2340
2443
|
end
|
2341
2444
|
end
|
2342
2445
|
# Returns the columns array
|
2446
|
+
puts_log "Inside def columns() #{columns}"
|
2343
2447
|
return columns
|
2344
2448
|
end
|
2345
|
-
|
2449
|
+
|
2450
|
+
def extract_default_function(default_value, default)
|
2451
|
+
default if has_default_function?(default_value, default)
|
2452
|
+
end
|
2453
|
+
|
2454
|
+
def has_default_function?(default_value, default)
|
2455
|
+
!default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
|
2456
|
+
end
|
2457
|
+
|
2346
2458
|
def foreign_keys(table_name)
|
2459
|
+
puts_log "foreign_keys #{table_name}"
|
2347
2460
|
#fetch the foreign keys of the table using function foreign_keys
|
2348
2461
|
#PKTABLE_NAME:: fk_row[2] Name of the table containing the primary key.
|
2349
2462
|
#PKCOLUMN_NAME:: fk_row[3] Name of the column containing the primary key.
|
@@ -2359,15 +2472,16 @@ module ActiveRecord
|
|
2359
2472
|
|
2360
2473
|
if(stmt)
|
2361
2474
|
begin
|
2362
|
-
while ( fk_row = IBM_DB.fetch_array(stmt) )
|
2475
|
+
while ( fk_row = IBM_DB.fetch_array(stmt) )
|
2476
|
+
puts_log "foreign_keys fetch = #{fk_row}"
|
2363
2477
|
options = {
|
2364
|
-
column: fk_row[7],
|
2365
|
-
name: fk_row[11],
|
2366
|
-
primary_key: fk_row[3],
|
2478
|
+
column: fk_row[7].downcase,
|
2479
|
+
name: fk_row[11].downcase,
|
2480
|
+
primary_key: fk_row[3].downcase,
|
2367
2481
|
}
|
2368
2482
|
options[:on_update] = extract_foreign_key_action(fk_row[9])
|
2369
2483
|
options[:on_delete] = extract_foreign_key_action(fk_row[10])
|
2370
|
-
foreignKeys << ForeignKeyDefinition.new(fk_row[6],
|
2484
|
+
foreignKeys << ForeignKeyDefinition.new(fk_row[6].downcase, fk_row[2].downcase, options)
|
2371
2485
|
end
|
2372
2486
|
|
2373
2487
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
@@ -2390,24 +2504,25 @@ module ActiveRecord
|
|
2390
2504
|
raise StandardError.new('An unexpected error occurred during foreign key retrieval')
|
2391
2505
|
end
|
2392
2506
|
end
|
2393
|
-
|
2394
|
-
|
2395
|
-
|
2507
|
+
#Returns the foreignKeys array
|
2508
|
+
return foreignKeys
|
2509
|
+
end
|
2396
2510
|
|
2397
|
-
|
2398
|
-
|
2399
|
-
|
2400
|
-
|
2401
|
-
|
2402
|
-
|
2403
|
-
|
2511
|
+
def extract_foreign_key_action(specifier) # :nodoc:
|
2512
|
+
puts_log "extract_foreign_key_action"
|
2513
|
+
case specifier
|
2514
|
+
when 0; :cascade
|
2515
|
+
when 1; :restrict
|
2516
|
+
when 2; :nullify
|
2517
|
+
end
|
2404
2518
|
end
|
2405
2519
|
|
2406
2520
|
def supports_disable_referential_integrity? #:nodoc:
|
2407
|
-
|
2408
|
-
|
2521
|
+
true
|
2522
|
+
end
|
2409
2523
|
|
2410
|
-
|
2524
|
+
def disable_referential_integrity #:nodoc:
|
2525
|
+
puts_log "disable_referential_integrity"
|
2411
2526
|
if supports_disable_referential_integrity?
|
2412
2527
|
alter_foreign_keys(tables, true)
|
2413
2528
|
end
|
@@ -2416,43 +2531,293 @@ module ActiveRecord
|
|
2416
2531
|
ensure
|
2417
2532
|
if supports_disable_referential_integrity?
|
2418
2533
|
alter_foreign_keys(tables, false)
|
2419
|
-
end
|
2420
|
-
|
2421
|
-
end
|
2534
|
+
end
|
2535
|
+
end
|
2422
2536
|
|
2423
2537
|
def alter_foreign_keys(tables, not_enforced)
|
2538
|
+
puts_log "alter_foreign_keys"
|
2424
2539
|
enforced = not_enforced ? 'NOT ENFORCED' : 'ENFORCED'
|
2425
2540
|
tables.each do |table|
|
2426
2541
|
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}")
|
2542
|
+
execute("ALTER TABLE #{@servertype.set_case(fk.from_table)} ALTER FOREIGN KEY #{@servertype.set_case(fk.name)} #{enforced}")
|
2543
|
+
end
|
2544
|
+
end
|
2545
|
+
end
|
2546
|
+
|
2547
|
+
def primary_keys(table_name) # :nodoc:
|
2548
|
+
puts_log "primary_keys"
|
2549
|
+
raise ArgumentError unless table_name.present?
|
2550
|
+
primary_key(table_name)
|
2551
|
+
end
|
2552
|
+
|
2553
|
+
# Adds comment for given table column or drops it if +comment+ is a +nil+
|
2554
|
+
def change_column_comment(table_name, column_name, comment_or_changes) # :nodoc:
|
2555
|
+
puts_log "change_column_comment"
|
2556
|
+
clear_cache!
|
2557
|
+
comment = extract_new_comment_value(comment_or_changes)
|
2558
|
+
if comment.nil?
|
2559
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS ''"
|
2560
|
+
else
|
2561
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
|
2562
|
+
end
|
2563
|
+
end
|
2564
|
+
|
2565
|
+
# Adds comment for given table or drops it if +comment+ is a +nil+
|
2566
|
+
def change_table_comment(table_name, comment_or_changes) # :nodoc:
|
2567
|
+
puts_log "change_table_comment"
|
2568
|
+
clear_cache!
|
2569
|
+
comment = extract_new_comment_value(comment_or_changes)
|
2570
|
+
if comment.nil?
|
2571
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS ''"
|
2572
|
+
else
|
2573
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
|
2574
|
+
end
|
2575
|
+
end
|
2576
|
+
|
2577
|
+
def add_column(table_name, column_name, type, **options) # :nodoc:
|
2578
|
+
puts_log "add_column"
|
2579
|
+
clear_cache!
|
2580
|
+
puts_log "add_column info #{table_name}, #{column_name}, #{type}, #{options}"
|
2581
|
+
if (!type.nil? && type.to_s == "primary_key") or (options.key?(:primary_key) and options[:primary_key] == true)
|
2582
|
+
if !type.nil? and type.to_s != "primary_key"
|
2583
|
+
execute "ALTER TABLE #{table_name} ADD COLUMN #{column_name} #{type} NOT NULL DEFAULT 0"
|
2584
|
+
else
|
2585
|
+
execute "ALTER TABLE #{table_name} ADD COLUMN #{column_name} INTEGER NOT NULL DEFAULT 0"
|
2428
2586
|
end
|
2587
|
+
execute "ALTER TABLE #{table_name} alter column #{column_name} drop default"
|
2588
|
+
execute "ALTER TABLE #{table_name} alter column #{column_name} set GENERATED BY DEFAULT AS IDENTITY (START WITH 1000)"
|
2589
|
+
execute "ALTER TABLE #{table_name} add primary key (#{column_name})"
|
2590
|
+
else
|
2591
|
+
super
|
2429
2592
|
end
|
2593
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
2594
|
+
end
|
2595
|
+
|
2596
|
+
def table_comment(table_name) # :nodoc:
|
2597
|
+
puts_log "table_comment"
|
2598
|
+
sql = "select remarks from syscat.tables where tabname = #{quote(table_name.upcase)}"
|
2599
|
+
single_value_from_rows(select_prepared(sql).rows)
|
2600
|
+
end
|
2601
|
+
|
2602
|
+
def add_index(table_name, column_name, **options) #:nodoc:
|
2603
|
+
puts_log "add_index"
|
2604
|
+
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
2605
|
+
|
2606
|
+
return if if_not_exists && index_exists?(table_name, column_name, name: index.name)
|
2607
|
+
if_not_exists = false if if_not_exists
|
2608
|
+
create_index = CreateIndexDefinition.new(index, algorithm, if_not_exists)
|
2609
|
+
result = execute schema_creation.accept(create_index)
|
2610
|
+
|
2611
|
+
execute "COMMENT ON INDEX #{quote_column_name(index.name)} IS #{quote(index.comment)}" if index.comment
|
2612
|
+
result
|
2613
|
+
end
|
2614
|
+
|
2615
|
+
def query_values(sql, name = nil) # :nodoc:
|
2616
|
+
puts_log "query_values"
|
2617
|
+
select_prepared(sql).rows.map(&:first)
|
2618
|
+
end
|
2619
|
+
|
2620
|
+
def data_source_sql(name = nil, type: nil)
|
2621
|
+
puts_log "data_source_sql"
|
2622
|
+
sql = +"SELECT tabname FROM (SELECT tabname, type FROM syscat.tables "
|
2623
|
+
sql << " WHERE tabschema = #{quote(@schema.upcase)}) subquery"
|
2624
|
+
if type || name
|
2625
|
+
conditions = []
|
2626
|
+
conditions << "subquery.type = #{quote(type.upcase)}" if type
|
2627
|
+
conditions << "subquery.tabname = #{quote(name.upcase)}" if name
|
2628
|
+
sql << " WHERE #{conditions.join(" AND ")}"
|
2629
|
+
end
|
2630
|
+
sql
|
2430
2631
|
end
|
2431
2632
|
|
2633
|
+
# Returns an array of table names defined in the database.
|
2634
|
+
def tables
|
2635
|
+
puts_log "tables"
|
2636
|
+
query_values(data_source_sql(type: "T"), "SCHEMA").map(&:downcase)
|
2637
|
+
end
|
2638
|
+
|
2639
|
+
# Checks to see if the table +table_name+ exists on the database.
|
2640
|
+
#
|
2641
|
+
# table_exists?(:developers)
|
2642
|
+
#
|
2643
|
+
def table_exists?(table_name)
|
2644
|
+
puts_log "table_exists? = #{table_name}"
|
2645
|
+
query_values(data_source_sql(table_name, type: "T"), "SCHEMA").any? if table_name.present?
|
2646
|
+
rescue NotImplementedError
|
2647
|
+
tables.include?(table_name.to_s)
|
2648
|
+
end
|
2649
|
+
|
2650
|
+
# Returns an array of view names defined in the database.
|
2651
|
+
def views
|
2652
|
+
puts_log "views"
|
2653
|
+
query_values(data_source_sql(type: "V"), "SCHEMA").map(&:downcase)
|
2654
|
+
end
|
2655
|
+
|
2656
|
+
# Checks to see if the view +view_name+ exists on the database.
|
2657
|
+
#
|
2658
|
+
# view_exists?(:ebooks)
|
2659
|
+
#
|
2660
|
+
def view_exists?(view_name)
|
2661
|
+
puts_log "view_exists?"
|
2662
|
+
query_values(data_source_sql(view_name, type: "V"), "SCHEMA").any? if view_name.present?
|
2663
|
+
rescue NotImplementedError
|
2664
|
+
views.include?(view_name.to_s)
|
2665
|
+
end
|
2666
|
+
|
2667
|
+
# Returns the relation names useable to back Active Record models.
|
2668
|
+
# For most adapters this means all #tables and #views.
|
2669
|
+
def data_sources
|
2670
|
+
puts_log "data_sources"
|
2671
|
+
query_values(data_source_sql, "SCHEMA").map(&:downcase)
|
2672
|
+
rescue NotImplementedError
|
2673
|
+
tables | views
|
2674
|
+
end
|
2675
|
+
|
2676
|
+
def create_schema_dumper(options)
|
2677
|
+
puts_log "create_schema_dumper"
|
2678
|
+
SchemaDumper.create(self, options)
|
2679
|
+
end
|
2680
|
+
|
2681
|
+
def table_options(table_name) # :nodoc:
|
2682
|
+
puts_log "table_options"
|
2683
|
+
if comment = table_comment(table_name)
|
2684
|
+
{ comment: comment }
|
2685
|
+
end
|
2686
|
+
end
|
2687
|
+
|
2432
2688
|
# Renames a table.
|
2433
2689
|
# ==== Example
|
2434
2690
|
# rename_table('octopuses', 'octopi')
|
2435
2691
|
# Overriden to satisfy IBM data servers syntax
|
2436
2692
|
def rename_table(name, new_name)
|
2693
|
+
puts_log "rename_table"
|
2694
|
+
name = quote_column_name(name)
|
2695
|
+
new_name = quote_column_name(new_name)
|
2696
|
+
puts_log "90 old_table = #{name}, new_table = #{new_name}"
|
2437
2697
|
# SQL rename table statement
|
2698
|
+
index_list = indexes(name)
|
2699
|
+
puts_log "Index List = #{index_list}"
|
2700
|
+
drop_table_indexes(index_list)
|
2438
2701
|
rename_table_sql = "RENAME TABLE #{name} TO #{new_name}"
|
2439
2702
|
stmt = execute(rename_table_sql)
|
2703
|
+
create_table_indexes(index_list, new_name)
|
2440
2704
|
# Ensures to free the resources associated with the statement
|
2441
2705
|
ensure
|
2442
2706
|
IBM_DB.free_stmt(stmt) if stmt
|
2443
2707
|
end
|
2444
2708
|
|
2445
|
-
|
2446
|
-
|
2447
|
-
|
2448
|
-
|
2449
|
-
|
2709
|
+
def drop_table_indexes(index_list)
|
2710
|
+
puts_log "drop_table_indexes"
|
2711
|
+
index_list.each do |indexs|
|
2712
|
+
remove_index(indexs.table, name: indexs.name)
|
2713
|
+
end
|
2714
|
+
end
|
2715
|
+
|
2716
|
+
def create_table_indexes(index_list, new_table)
|
2717
|
+
puts_log "create_table_indexes"
|
2718
|
+
index_list.each do |indexs|
|
2719
|
+
generated_index_name = index_name(indexs.table, column: indexs.columns)
|
2720
|
+
custom_index_name = indexs.name
|
2721
|
+
|
2722
|
+
if generated_index_name == custom_index_name
|
2723
|
+
add_index(new_table, indexs.columns, unique: indexs.unique)
|
2724
|
+
else
|
2725
|
+
add_index(new_table, indexs.columns, name: custom_index_name, unique: indexs.unique)
|
2726
|
+
end
|
2727
|
+
end
|
2728
|
+
end
|
2729
|
+
|
2730
|
+
def drop_column_indexes(index_list, column_name)
|
2731
|
+
puts_log "drop_column_indexes"
|
2732
|
+
index_list.each do |indexs|
|
2733
|
+
if indexs.columns.class == Array
|
2734
|
+
next if !indexs.columns.include?(column_name)
|
2735
|
+
else
|
2736
|
+
next if indexs.columns != column_name
|
2737
|
+
end
|
2738
|
+
remove_index(indexs.table, name: indexs.name)
|
2739
|
+
end
|
2740
|
+
end
|
2741
|
+
|
2742
|
+
def create_column_indexes(index_list, column_name, new_column_name)
|
2743
|
+
puts_log "create_column_indexes"
|
2744
|
+
index_list.each do |indexs|
|
2745
|
+
generated_index_name = index_name(indexs.table, column: indexs.columns)
|
2746
|
+
custom_index_name = indexs.name
|
2747
|
+
if indexs.columns.class == Array
|
2748
|
+
next if !indexs.columns.include?(column_name)
|
2749
|
+
indexs.columns[indexs.columns.index(column_name)] = new_column_name
|
2750
|
+
else
|
2751
|
+
next if indexs.columns != column_name
|
2752
|
+
indexs.columns = new_column_name
|
2753
|
+
end
|
2754
|
+
|
2755
|
+
if generated_index_name == custom_index_name
|
2756
|
+
add_index(indexs.table, indexs.columns, unique: indexs.unique)
|
2757
|
+
else
|
2758
|
+
add_index(indexs.table, indexs.columns, name: custom_index_name, unique: indexs.unique)
|
2759
|
+
end
|
2760
|
+
end
|
2761
|
+
end
|
2762
|
+
|
2763
|
+
# Renames a column in a table.
|
2764
|
+
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
2765
|
+
puts_log "rename_column"
|
2766
|
+
column_name = quote_column_name(column_name)
|
2767
|
+
new_column_name = quote_column_name(new_column_name)
|
2768
|
+
puts_log "rename_column #{table_name}, #{column_name}, #{new_column_name}"
|
2769
|
+
clear_cache!
|
2770
|
+
index_list = indexes(table_name)
|
2771
|
+
puts_log "Index List = #{index_list}"
|
2772
|
+
fkey_list = foreign_keys(table_name)
|
2773
|
+
puts_log "ForeignKey = #{fkey_list}"
|
2774
|
+
drop_column_indexes(index_list, column_name)
|
2775
|
+
fkey_removed = remove_foreign_key_byColumn(fkey_list, table_name, column_name)
|
2776
|
+
execute("ALTER TABLE #{quote_table_name(table_name)} #{rename_column_sql(table_name, column_name, new_column_name)}")
|
2777
|
+
add_foreign_keyList(fkey_list, table_name, column_name, new_column_name) if fkey_removed
|
2778
|
+
create_column_indexes(index_list, column_name, new_column_name)
|
2779
|
+
end
|
2780
|
+
|
2781
|
+
def add_foreign_keyList(fkey_list, table_name, column_name, new_column_name)
|
2782
|
+
puts_log "add_foreign_keyList = #{table_name}, #{column_name}, #{fkey_list}"
|
2783
|
+
fkey_list.each do |fkey|
|
2784
|
+
if fkey.options[:column] == column_name
|
2785
|
+
add_foreign_key(table_name, fkey.to_table, column: new_column_name)
|
2786
|
+
end
|
2787
|
+
end
|
2788
|
+
end
|
2789
|
+
|
2790
|
+
def remove_foreign_key_byColumn(fkey_list, table_name, column_name)
|
2791
|
+
puts_log "remove_foreign_key_byColumn = #{table_name}, #{column_name}, #{fkey_list}"
|
2792
|
+
fkey_removed = false
|
2793
|
+
fkey_list.each do |fkey|
|
2794
|
+
if fkey.options[:column] == column_name
|
2795
|
+
remove_foreign_key(table_name, column: column_name)
|
2796
|
+
fkey_removed = true
|
2797
|
+
end
|
2798
|
+
end
|
2799
|
+
fkey_removed
|
2800
|
+
end
|
2801
|
+
|
2802
|
+
def rename_index(table_name, old_name, new_name)
|
2803
|
+
puts_log "rename_index"
|
2804
|
+
old_name = old_name.to_s
|
2805
|
+
new_name = new_name.to_s
|
2806
|
+
validate_index_length!(table_name, new_name)
|
2807
|
+
|
2808
|
+
# this is a naive implementation; some DBs may support this more efficiently (PostgreSQL, for instance)
|
2809
|
+
old_index_def = indexes(table_name).detect { |i| i.name == old_name }
|
2810
|
+
return unless old_index_def
|
2811
|
+
remove_index(table_name, name: old_name)
|
2812
|
+
add_index(table_name, old_index_def.columns, name: new_name, unique: old_index_def.unique)
|
2450
2813
|
end
|
2451
2814
|
|
2452
2815
|
# Removes the column from the table definition.
|
2453
2816
|
# ===== Examples
|
2454
2817
|
# remove_column(:suppliers, :qualification)
|
2455
|
-
def remove_column(table_name, column_name)
|
2818
|
+
def remove_column(table_name, column_name, type = nil, **options)
|
2819
|
+
puts_log "remove_column"
|
2820
|
+
return if options[:if_exists] == true && !column_exists?(table_name, column_name)
|
2456
2821
|
@servertype.remove_column(table_name, column_name)
|
2457
2822
|
end
|
2458
2823
|
|
@@ -2462,28 +2827,20 @@ module ActiveRecord
|
|
2462
2827
|
# change_column(:suppliers, :name, :string, :limit => 80)
|
2463
2828
|
# change_column(:accounts, :description, :text)
|
2464
2829
|
def change_column(table_name, column_name, type, options = {})
|
2830
|
+
puts_log "change_column"
|
2465
2831
|
@servertype.change_column(table_name, column_name, type, options)
|
2832
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
2466
2833
|
end
|
2467
2834
|
|
2468
2835
|
#Add distinct clause to the sql if there is no order by specified
|
2469
2836
|
def distinct(columns, order_by)
|
2837
|
+
puts_log "distinct"
|
2470
2838
|
if order_by.nil?
|
2471
2839
|
"DISTINCT #{columns}"
|
2472
2840
|
else
|
2473
2841
|
"#{columns}"
|
2474
2842
|
end
|
2475
2843
|
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
2844
|
|
2488
2845
|
# Sets a new default value for a column. This does not set the default
|
2489
2846
|
# value to +NULL+, instead, it needs DatabaseStatements#execute which
|
@@ -2493,43 +2850,42 @@ module ActiveRecord
|
|
2493
2850
|
# change_column_default(:accounts, :authorized, 1)
|
2494
2851
|
# Method overriden to satisfy IBM data servers syntax.
|
2495
2852
|
def change_column_default(table_name, column_name, default)
|
2853
|
+
puts_log "change_column_default"
|
2496
2854
|
@servertype.change_column_default(table_name, column_name, default)
|
2497
2855
|
end
|
2498
2856
|
|
2499
2857
|
#Changes the nullability value of a column
|
2500
2858
|
def change_column_null(table_name, column_name, null, default = nil)
|
2859
|
+
puts_log "change_column_null"
|
2501
2860
|
@servertype.change_column_null(table_name, column_name, null, default)
|
2502
2861
|
end
|
2503
2862
|
|
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)}")
|
2863
|
+
def remove_index(table_name, column_name = nil, **options)
|
2864
|
+
puts_log "remove_index"
|
2865
|
+
return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
|
2866
|
+
execute("DROP INDEX #{index_name_for_remove(table_name, column_name, options)}")
|
2867
|
+
end
|
2868
|
+
|
2869
|
+
def column_for(table_name, column_name)
|
2870
|
+
super
|
2519
2871
|
end
|
2520
2872
|
|
2521
2873
|
protected
|
2522
|
-
def initialize_type_map(m) # :nodoc:
|
2874
|
+
def initialize_type_map(m = type_map) # :nodoc:
|
2875
|
+
puts_log "initialize_type_map"
|
2523
2876
|
register_class_with_limit m, %r(boolean)i, Type::Boolean
|
2524
2877
|
register_class_with_limit m, %r(char)i, Type::String
|
2525
2878
|
register_class_with_limit m, %r(binary)i, Type::Binary
|
2526
2879
|
register_class_with_limit m, %r(text)i, Type::Text
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2880
|
+
register_class_with_precision m, %r(date)i, Type::Date
|
2881
|
+
register_class_with_precision m, %r(time)i, Type::Time
|
2882
|
+
register_class_with_precision m, %r(datetime)i, Type::DateTime
|
2530
2883
|
register_class_with_limit m, %r(float)i, Type::Float
|
2531
|
-
|
2532
|
-
|
2884
|
+
|
2885
|
+
m.register_type %r(^bigint)i, Type::Integer.new(limit: 8)
|
2886
|
+
m.register_type %r(^int)i, Type::Integer.new(limit: 4)
|
2887
|
+
m.register_type %r(^smallint)i, Type::Integer.new(limit: 2)
|
2888
|
+
m.register_type %r(^tinyint)i, Type::Integer.new(limit: 1)
|
2533
2889
|
|
2534
2890
|
m.alias_type %r(blob)i, 'binary'
|
2535
2891
|
m.alias_type %r(clob)i, 'text'
|
@@ -2552,13 +2908,20 @@ module ActiveRecord
|
|
2552
2908
|
|
2553
2909
|
m.alias_type %r(xml)i, 'text'
|
2554
2910
|
m.alias_type %r(for bit data)i, 'binary'
|
2555
|
-
m.alias_type %r(smallint)i, 'boolean'
|
2556
2911
|
m.alias_type %r(serial)i, 'int'
|
2557
2912
|
m.alias_type %r(decfloat)i, 'decimal'
|
2558
2913
|
m.alias_type %r(real)i, 'decimal'
|
2559
2914
|
m.alias_type %r(graphic)i, 'binary'
|
2560
2915
|
m.alias_type %r(rowid)i, 'int'
|
2561
2916
|
end
|
2917
|
+
|
2918
|
+
class SchemaDumper < ConnectionAdapters::SchemaDumper
|
2919
|
+
def dump(stream) # Like in abstract class, we no need to call header() & trailer().
|
2920
|
+
extensions(stream)
|
2921
|
+
tables(stream)
|
2922
|
+
stream
|
2923
|
+
end
|
2924
|
+
end
|
2562
2925
|
end # class IBM_DBAdapter
|
2563
2926
|
|
2564
2927
|
# This class contains common code across DB's (DB2 LUW, zOS, i5 and IDS)
|
@@ -2581,12 +2944,14 @@ module ActiveRecord
|
|
2581
2944
|
end
|
2582
2945
|
|
2583
2946
|
def check_reserved_words(col_name)
|
2947
|
+
@adapter.puts_log "check_reserved_words"
|
2584
2948
|
col_name.to_s
|
2585
2949
|
end
|
2586
2950
|
|
2587
2951
|
# This is supported by the DB2 for Linux, UNIX, Windows data servers
|
2588
2952
|
# and by the DB2 for i5 data servers
|
2589
2953
|
def remove_column(table_name, column_name)
|
2954
|
+
@adapter.puts_log "remove_column"
|
2590
2955
|
begin
|
2591
2956
|
@adapter.execute "ALTER TABLE #{table_name} DROP #{column_name}"
|
2592
2957
|
reorg_table(table_name)
|
@@ -2603,12 +2968,13 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2603
2968
|
end
|
2604
2969
|
|
2605
2970
|
def select(stmt)
|
2971
|
+
@adapter.puts_log "select"
|
2606
2972
|
results = []
|
2607
2973
|
# Fetches all the results available. IBM_DB.fetch_assoc(stmt) returns
|
2608
2974
|
# an hash for each single record.
|
2609
2975
|
# The loop stops when there aren't any more valid records to fetch
|
2610
2976
|
begin
|
2611
|
-
|
2977
|
+
if(@isAr3)
|
2612
2978
|
while single_hash = IBM_DB.fetch_assoc(stmt)
|
2613
2979
|
# Add the record to the +results+ array
|
2614
2980
|
results << single_hash
|
@@ -2633,6 +2999,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2633
2999
|
end
|
2634
3000
|
|
2635
3001
|
def select_rows(sql, name, stmt, results)
|
3002
|
+
@adapter.puts_log "select_rows"
|
2636
3003
|
# Fetches all the results available. IBM_DB.fetch_array(stmt) returns
|
2637
3004
|
# an array representing a row in a result set.
|
2638
3005
|
# The loop stops when there aren't any more valid records to fetch
|
@@ -2656,6 +3023,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2656
3023
|
|
2657
3024
|
# Praveen
|
2658
3025
|
def prepare(sql,name = nil)
|
3026
|
+
@adapter.puts_log "prepare"
|
2659
3027
|
begin
|
2660
3028
|
stmt = IBM_DB.prepare(@adapter.connection, sql)
|
2661
3029
|
if( stmt )
|
@@ -2667,61 +3035,39 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2667
3035
|
if prep_err && !prep_err.message.empty?
|
2668
3036
|
raise "Failed to prepare sql #{sql} due to: #{prep_err}"
|
2669
3037
|
else
|
2670
|
-
raise
|
3038
|
+
raise "An unexpected error occurred during SQLprepare"
|
2671
3039
|
end
|
2672
3040
|
end
|
2673
3041
|
end
|
2674
3042
|
|
2675
3043
|
# Akhil Tcheck for if_exits added so that it will try to drop even if the table does not exit.
|
2676
3044
|
def execute(sql, name = nil)
|
2677
|
-
|
3045
|
+
@adapter.puts_log "execute #{sql}"
|
3046
|
+
|
2678
3047
|
begin
|
2679
|
-
if
|
3048
|
+
if @adapter.connection == nil || @adapter.connection == false
|
3049
|
+
raise ActiveRecord::ConnectionNotEstablished, "called on a closed database"
|
3050
|
+
elsif stmt = IBM_DB.exec(@adapter.connection, sql)
|
2680
3051
|
stmt # Return the statement object
|
2681
3052
|
else
|
2682
|
-
raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN )
|
3053
|
+
raise StatementInvalid, IBM_DB.getErrormsg(@adapter.connection, IBM_DB::DB_CONN ), sql
|
2683
3054
|
end
|
2684
3055
|
rescue StandardError => exec_err
|
2685
3056
|
if exec_err && !exec_err.message.empty?
|
2686
|
-
|
3057
|
+
@adapter.puts_log "104 error = #{exec_err.message}"
|
3058
|
+
@adapter.puts_log "104 sql = #{sql}"
|
3059
|
+
raise StatementInvalid
|
2687
3060
|
else
|
2688
3061
|
raise
|
2689
3062
|
end
|
2690
3063
|
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
3064
|
end
|
2711
3065
|
|
2712
3066
|
def set_schema(schema)
|
3067
|
+
@adapter.puts_log "set_schema"
|
2713
3068
|
@adapter.execute("SET SCHEMA #{schema}")
|
2714
3069
|
end
|
2715
3070
|
|
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
3071
|
def get_datetime_mapping
|
2726
3072
|
end
|
2727
3073
|
|
@@ -2761,10 +3107,12 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2761
3107
|
end
|
2762
3108
|
|
2763
3109
|
def rename_column(table_name, column_name, new_column_name)
|
3110
|
+
@adapter.puts_log "primary_key_definition"
|
2764
3111
|
raise NotImplementedError, "rename_column is not implemented yet in the IBM_DB Adapter"
|
2765
3112
|
end
|
2766
3113
|
|
2767
3114
|
def primary_key_definition(start_id)
|
3115
|
+
@adapter.puts_log "108"
|
2768
3116
|
return "INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH #{start_id}) PRIMARY KEY NOT NULL"
|
2769
3117
|
end
|
2770
3118
|
|
@@ -2773,6 +3121,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2773
3121
|
# The "stmt" parameter is ignored for DB2 but used for IDS
|
2774
3122
|
def last_generated_id(stmt)
|
2775
3123
|
# Queries the db to obtain the last ID that was automatically generated
|
3124
|
+
@adapter.puts_log "last_generated_id"
|
2776
3125
|
sql = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1"
|
2777
3126
|
stmt = IBM_DB.prepare(@adapter.connection, sql)
|
2778
3127
|
if(stmt)
|
@@ -2781,7 +3130,8 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2781
3130
|
# Fetches the only record available (containing the last id)
|
2782
3131
|
IBM_DB.fetch_row(stmt)
|
2783
3132
|
# Retrieves and returns the result of the query with the last id.
|
2784
|
-
IBM_DB.result(stmt,0)
|
3133
|
+
id_value = IBM_DB.result(stmt,0)
|
3134
|
+
return id_value.to_i
|
2785
3135
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
2786
3136
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
2787
3137
|
if error_msg && !error_msg.empty?
|
@@ -2815,33 +3165,54 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
2815
3165
|
end
|
2816
3166
|
|
2817
3167
|
def change_column(table_name, column_name, type, options)
|
2818
|
-
|
2819
|
-
|
2820
|
-
else
|
3168
|
+
@adapter.puts_log "change_column #{table_name.to_s}, #{column_name.to_s}, #{type.to_s}"
|
3169
|
+
column = @adapter.column_for(table_name, column_name)
|
2821
3170
|
data_type = @adapter.type_to_sql(type, options[:limit], options[:precision], options[:scale])
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2828
|
-
|
2829
|
-
|
2830
|
-
|
3171
|
+
|
3172
|
+
if column.sql_type != data_type
|
3173
|
+
begin
|
3174
|
+
execute "ALTER TABLE #{table_name} ALTER #{column_name} SET DATA TYPE #{data_type}"
|
3175
|
+
rescue StandardError => exec_err
|
3176
|
+
if exec_err.message.include?('SQLCODE=-190')
|
3177
|
+
raise StatementInvalid,
|
3178
|
+
"Please consult documentation for compatible data types while changing column datatype. \
|
3179
|
+
The column datatype change to [#{data_type}] is not supported by this data server: #{exec_err}"
|
3180
|
+
else
|
3181
|
+
raise "#{exec_err}"
|
3182
|
+
end
|
2831
3183
|
end
|
3184
|
+
reorg_table(table_name)
|
3185
|
+
end
|
3186
|
+
|
3187
|
+
if options.key?(:default)
|
3188
|
+
change_column_default(table_name, column_name, options[:default])
|
3189
|
+
end
|
3190
|
+
if options.key?(:null)
|
3191
|
+
change_column_null(table_name, column_name, options[:null], nil)
|
3192
|
+
end
|
3193
|
+
end
|
3194
|
+
|
3195
|
+
def extract_new_default_value(default_or_changes)
|
3196
|
+
@adapter.puts_log "extract_new_default_value"
|
3197
|
+
if default_or_changes.is_a?(Hash) && default_or_changes.has_key?(:from) && default_or_changes.has_key?(:to)
|
3198
|
+
default_or_changes[:to]
|
3199
|
+
else
|
3200
|
+
default_or_changes
|
2832
3201
|
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
3202
|
end
|
2838
|
-
end
|
2839
3203
|
|
2840
3204
|
# DB2 specific ALTER TABLE statement to add a default clause
|
2841
3205
|
def change_column_default(table_name, column_name, default)
|
3206
|
+
@adapter.puts_log "change_column_default #{table_name.to_s} #{column_name.to_s}"
|
3207
|
+
@adapter.puts_log "Default: #{default}"
|
3208
|
+
|
3209
|
+
default = extract_new_default_value(default)
|
2842
3210
|
# SQL statement which alters column's default value
|
2843
|
-
|
2844
|
-
SET WITH DEFAULT
|
3211
|
+
if default.nil?
|
3212
|
+
change_column_sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT NULL"
|
3213
|
+
else
|
3214
|
+
change_column_sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{@adapter.quote(default)}"
|
3215
|
+
end
|
2845
3216
|
|
2846
3217
|
stmt = execute(change_column_sql)
|
2847
3218
|
reorg_table(table_name)
|
@@ -2851,6 +3222,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2851
3222
|
|
2852
3223
|
#DB2 specific ALTER TABLE statement to change the nullability of a column
|
2853
3224
|
def change_column_null(table_name, column_name, null, default)
|
3225
|
+
@adapter.puts_log "change_column_null #{table_name.to_s} #{column_name.to_s}"
|
2854
3226
|
if !default.nil?
|
2855
3227
|
change_column_default(table_name, column_name, default)
|
2856
3228
|
end
|
@@ -2872,131 +3244,47 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2872
3244
|
# This method returns the DB2 SQL type corresponding to the Rails
|
2873
3245
|
# datetime/timestamp type
|
2874
3246
|
def get_datetime_mapping
|
3247
|
+
@adapter.puts_log "get_datetime_mapping"
|
2875
3248
|
return "timestamp"
|
2876
3249
|
end
|
2877
3250
|
|
2878
3251
|
# This method returns the DB2 SQL type corresponding to the Rails
|
2879
3252
|
# time type
|
2880
3253
|
def get_time_mapping
|
3254
|
+
@adapter.puts_log "get_time_mapping"
|
2881
3255
|
return "time"
|
2882
3256
|
end
|
2883
3257
|
|
2884
3258
|
#This method returns the DB2 SQL type corresponding to Rails double type
|
2885
3259
|
def get_double_mapping
|
3260
|
+
@adapter.puts_log "get_double_mapping"
|
2886
3261
|
return "double"
|
2887
3262
|
end
|
2888
3263
|
|
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
3264
|
# This method generates the default blob value specified for
|
2981
3265
|
# DB2 Dataservers
|
2982
3266
|
def set_binary_default(value)
|
3267
|
+
@adapter.puts_log "set_binary_default"
|
2983
3268
|
"BLOB('#{value}')"
|
2984
3269
|
end
|
2985
3270
|
|
2986
3271
|
# This method generates the blob value specified for DB2 Dataservers
|
2987
3272
|
def set_binary_value
|
3273
|
+
@adapter.puts_log "set_binary_value"
|
2988
3274
|
"BLOB('?')"
|
2989
3275
|
end
|
2990
3276
|
|
2991
3277
|
# This method generates the default clob value specified for
|
2992
3278
|
# DB2 Dataservers
|
2993
3279
|
def set_text_default(value)
|
3280
|
+
@adapter.puts_log "set_text_default"
|
2994
3281
|
"'#{value}'"
|
2995
3282
|
end
|
2996
3283
|
|
2997
3284
|
# For DB2 Dataservers , the arguments to the meta-data functions
|
2998
3285
|
# need to be in upper-case
|
2999
3286
|
def set_case(value)
|
3287
|
+
@adapter.puts_log "set_case"
|
3000
3288
|
value.upcase
|
3001
3289
|
end
|
3002
3290
|
end # class IBM_DB2
|
@@ -3059,6 +3347,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
3059
3347
|
if rfile
|
3060
3348
|
RESERVED_WORDS = open(rfile.to_s) {|f| YAML.load(f) }
|
3061
3349
|
def check_reserved_words(col_name)
|
3350
|
+
puts_log "164"
|
3062
3351
|
if RESERVED_WORDS[col_name]
|
3063
3352
|
'"' + RESERVED_WORDS[col_name] + '"'
|
3064
3353
|
else
|
@@ -3140,28 +3429,6 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
3140
3429
|
class IBM_DB2_ZOS_8 < IBM_DB2_ZOS
|
3141
3430
|
include HostedDataServer
|
3142
3431
|
|
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
3432
|
# This call is needed on DB2 z/OS v8 for the creation of tables
|
3166
3433
|
# with LOBs. When issued, this call does the following:
|
3167
3434
|
# DB2 creates LOB table spaces, auxiliary tables, and indexes on auxiliary
|
@@ -3310,56 +3577,6 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
3310
3577
|
return "double precision"
|
3311
3578
|
end
|
3312
3579
|
|
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
3580
|
# Method that returns the last automatically generated ID
|
3364
3581
|
# on the given +@connection+. This method is required by the +insert+
|
3365
3582
|
# method. IDS returns the last generated serial value in the SQLCA unlike
|
@@ -3406,72 +3623,73 @@ end # module ActiveRecord
|
|
3406
3623
|
|
3407
3624
|
module Arel
|
3408
3625
|
#Check Arel version
|
3409
|
-
|
3410
|
-
|
3411
|
-
|
3412
|
-
|
3413
|
-
|
3414
|
-
if(arelVersion >= 6)
|
3415
|
-
module Collectors
|
3416
|
-
|
3417
|
-
|
3418
|
-
|
3419
|
-
|
3626
|
+
begin
|
3627
|
+
arelVersion = Arel::VERSION.to_i
|
3628
|
+
rescue
|
3629
|
+
arelVersion = 0
|
3630
|
+
end
|
3631
|
+
if(arelVersion >= 6)
|
3632
|
+
module Collectors
|
3633
|
+
class Bind
|
3634
|
+
def changeFirstSegment(segment)
|
3635
|
+
@parts[0] = segment
|
3636
|
+
end
|
3420
3637
|
|
3421
|
-
|
3422
|
-
|
3423
|
-
|
3638
|
+
def changeEndSegment(segment)
|
3639
|
+
len = @parts.length
|
3640
|
+
@parts[len] = segment
|
3641
|
+
end
|
3424
3642
|
end
|
3425
3643
|
end
|
3426
3644
|
end
|
3427
|
-
end
|
3428
3645
|
|
3429
3646
|
module Visitors
|
3430
3647
|
class Visitor #opening and closing the class to ensure backward compatibility
|
3431
3648
|
end
|
3432
3649
|
|
3433
|
-
#Check Arel version
|
3434
|
-
|
3435
|
-
|
3436
|
-
|
3437
|
-
|
3438
|
-
|
3439
|
-
|
3440
|
-
|
3441
|
-
|
3442
|
-
|
3650
|
+
#Check Arel version
|
3651
|
+
begin
|
3652
|
+
arelVersion = Arel::VERSION.to_i
|
3653
|
+
rescue
|
3654
|
+
arelVersion = 0
|
3655
|
+
end
|
3656
|
+
|
3657
|
+
if(arelVersion >= 6 && arelVersion <= 9)
|
3658
|
+
class ToSql < Arel::Visitors::Reduce #opening and closing the class to ensure backward compatibility
|
3659
|
+
# In case when using Rails-2.3.x there is no arel used due to which the constructor has to be defined explicitly
|
3660
|
+
# to ensure the same code works on any version of Rails
|
3443
3661
|
|
3444
|
-
|
3445
|
-
|
3446
|
-
|
3447
|
-
|
3448
|
-
|
3449
|
-
|
3662
|
+
#Check Arel version
|
3663
|
+
begin
|
3664
|
+
@arelVersion = Arel::VERSION.to_i
|
3665
|
+
rescue
|
3666
|
+
@arelVersion = 0
|
3667
|
+
end
|
3450
3668
|
|
3451
|
-
|
3452
|
-
|
3453
|
-
|
3454
|
-
|
3455
|
-
|
3456
|
-
|
3457
|
-
|
3458
|
-
|
3669
|
+
if(@arelVersion >= 3)
|
3670
|
+
def initialize connection
|
3671
|
+
super()
|
3672
|
+
@connection = connection
|
3673
|
+
@schema_cache = connection.schema_cache if(connection.respond_to?(:schema_cache))
|
3674
|
+
@quoted_tables = {}
|
3675
|
+
@quoted_columns = {}
|
3676
|
+
@last_column = nil
|
3677
|
+
end
|
3459
3678
|
end
|
3460
3679
|
end
|
3461
|
-
|
3462
|
-
|
3463
|
-
|
3464
|
-
|
3465
|
-
# to ensure the same code works on any version of Rails
|
3680
|
+
else
|
3681
|
+
class ToSql < Arel::Visitors::Visitor #opening and closing the class to ensure backward compatibility
|
3682
|
+
# In case when using Rails-2.3.x there is no arel used due to which the constructor has to be defined explicitly
|
3683
|
+
# to ensure the same code works on any version of Rails
|
3466
3684
|
|
3467
3685
|
#Check Arel version
|
3468
|
-
|
3469
|
-
|
3686
|
+
begin
|
3687
|
+
@arelVersion = Arel::VERSION.to_i
|
3470
3688
|
rescue
|
3471
3689
|
@arelVersion = 0
|
3472
3690
|
end
|
3473
|
-
|
3474
|
-
|
3691
|
+
if(@arelVersion >= 3)
|
3692
|
+
def initialize connection
|
3475
3693
|
super()
|
3476
3694
|
@connection = connection
|
3477
3695
|
@schema_cache = connection.schema_cache if(connection.respond_to?(:schema_cache))
|
@@ -3482,42 +3700,42 @@ else
|
|
3482
3700
|
|
3483
3701
|
end
|
3484
3702
|
end
|
3485
|
-
|
3486
|
-
end
|
3487
|
-
|
3488
|
-
|
3489
|
-
class IBM_DB < Arel::Visitors::ToSql
|
3490
|
-
private
|
3703
|
+
end
|
3491
3704
|
|
3492
|
-
|
3493
|
-
|
3494
|
-
|
3705
|
+
class IBM_DB < Arel::Visitors::ToSql
|
3706
|
+
private
|
3707
|
+
def visit_Arel_Nodes_Limit(o, collector)
|
3708
|
+
collector << " FETCH FIRST "
|
3495
3709
|
visit o.expr, collector
|
3496
|
-
|
3710
|
+
collector << " ROWS ONLY "
|
3497
3711
|
end
|
3498
3712
|
|
3499
|
-
def visit_Arel_Nodes_Offset
|
3500
|
-
|
3713
|
+
def visit_Arel_Nodes_Offset(o, collector)
|
3714
|
+
collector << " OFFSET "
|
3715
|
+
visit o.expr, collector
|
3716
|
+
collector << " ROWS"
|
3501
3717
|
end
|
3718
|
+
|
3502
3719
|
def visit_Arel_Nodes_ValuesList(o, collector)
|
3503
|
-
|
3504
|
-
|
3505
|
-
|
3506
|
-
|
3507
|
-
|
3508
|
-
|
3509
|
-
|
3510
|
-
|
3511
|
-
|
3512
|
-
|
3513
|
-
|
3514
|
-
|
3515
|
-
end
|
3720
|
+
collector << "VALUES "
|
3721
|
+
o.rows.each_with_index do |row, i|
|
3722
|
+
collector << ", " unless i == 0
|
3723
|
+
collector << "("
|
3724
|
+
row.each_with_index do |value, k|
|
3725
|
+
collector << ", " unless k == 0
|
3726
|
+
case value
|
3727
|
+
when Nodes::SqlLiteral, Nodes::BindParam
|
3728
|
+
collector = visit(value, collector)
|
3729
|
+
#collector << quote(value).to_s
|
3730
|
+
else
|
3731
|
+
collector << quote(value).to_s
|
3516
3732
|
end
|
3517
|
-
collector << ")"
|
3518
3733
|
end
|
3519
|
-
collector
|
3734
|
+
collector << ")"
|
3735
|
+
end
|
3736
|
+
collector
|
3520
3737
|
end
|
3738
|
+
|
3521
3739
|
def visit_Arel_Nodes_SelectStatement o, collector
|
3522
3740
|
if o.with
|
3523
3741
|
collector = visit o.with, collector
|
@@ -3533,61 +3751,27 @@ end
|
|
3533
3751
|
len = o.orders.length - 1
|
3534
3752
|
o.orders.each_with_index { |x, i|
|
3535
3753
|
collector = visit(x, collector)
|
3536
|
-
collector << "," unless len == i
|
3754
|
+
collector << ", " unless len == i
|
3537
3755
|
}
|
3538
3756
|
end
|
3539
3757
|
|
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
|
3758
|
+
if (o.offset && o.limit)
|
3759
|
+
visit_Arel_Nodes_Offset(o.offset, collector)
|
3760
|
+
visit_Arel_Nodes_Limit(o.limit, collector)
|
3761
|
+
elsif (o.offset && o.limit.nil?)
|
3762
|
+
collector << " OFFSET "
|
3763
|
+
visit o.offset.expr, collector
|
3764
|
+
collector << " ROWS "
|
3765
|
+
maybe_visit o.lock, collector
|
3766
|
+
else
|
3767
|
+
visit_Arel_Nodes_SelectOptions(o, collector)
|
3768
|
+
end
|
3769
|
+
end
|
3770
|
+
|
3771
|
+
# Locks are not supported in SQLite
|
3772
|
+
def visit_Arel_Nodes_Lock(o, collector)
|
3773
|
+
collector
|
3589
3774
|
end
|
3590
|
-
|
3591
3775
|
end
|
3592
3776
|
end
|
3593
3777
|
end
|