activerecord 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +4928 -3
- data/README +45 -46
- data/RUNNING_UNIT_TESTS +8 -11
- data/Rakefile +247 -0
- data/install.rb +8 -38
- data/lib/active_record/aggregations.rb +64 -49
- data/lib/active_record/associations/association_collection.rb +217 -47
- data/lib/active_record/associations/association_proxy.rb +159 -0
- data/lib/active_record/associations/belongs_to_association.rb +56 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +155 -37
- data/lib/active_record/associations/has_many_association.rb +145 -75
- data/lib/active_record/associations/has_many_through_association.rb +283 -0
- data/lib/active_record/associations/has_one_association.rb +96 -0
- data/lib/active_record/associations.rb +1537 -304
- data/lib/active_record/attribute_methods.rb +328 -0
- data/lib/active_record/base.rb +2001 -588
- data/lib/active_record/calculations.rb +269 -0
- data/lib/active_record/callbacks.rb +169 -165
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +308 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +472 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +306 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +125 -279
- data/lib/active_record/connection_adapters/mysql_adapter.rb +442 -77
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +805 -135
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +353 -69
- data/lib/active_record/fixtures.rb +946 -100
- data/lib/active_record/locking/optimistic.rb +144 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +417 -0
- data/lib/active_record/observer.rb +142 -32
- data/lib/active_record/query_cache.rb +23 -0
- data/lib/active_record/reflection.rb +163 -70
- data/lib/active_record/schema.rb +58 -0
- data/lib/active_record/schema_dumper.rb +171 -0
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/serializers/xml_serializer.rb +315 -0
- data/lib/active_record/timestamp.rb +41 -0
- data/lib/active_record/transactions.rb +87 -57
- data/lib/active_record/validations.rb +909 -122
- data/lib/active_record/vendor/db2.rb +362 -0
- data/lib/active_record/vendor/mysql.rb +126 -29
- data/lib/active_record/version.rb +9 -0
- data/lib/active_record.rb +35 -7
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +72 -0
- data/test/abstract_unit.rb +73 -5
- data/test/active_schema_test_mysql.rb +43 -0
- data/test/adapter_test.rb +105 -0
- data/test/adapter_test_sqlserver.rb +95 -0
- data/test/aggregations_test.rb +110 -16
- data/test/all.sh +2 -2
- data/test/ar_schema_test.rb +33 -0
- data/test/association_inheritance_reload.rb +14 -0
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +147 -0
- data/test/associations/cascaded_eager_loading_test.rb +110 -0
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +442 -0
- data/test/associations/extension_test.rb +47 -0
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +553 -0
- data/test/associations_test.rb +1930 -267
- data/test/attribute_methods_test.rb +146 -0
- data/test/base_test.rb +1316 -84
- data/test/binary_test.rb +32 -0
- data/test/calculations_test.rb +251 -0
- data/test/callbacks_test.rb +400 -0
- data/test/class_inheritable_attributes_test.rb +3 -4
- data/test/column_alias_test.rb +17 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_db2/connection.rb +25 -0
- data/test/connections/native_firebird/connection.rb +26 -0
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +21 -18
- data/test/connections/native_openbase/connection.rb +21 -0
- data/test/connections/native_oracle/connection.rb +27 -0
- data/test/connections/native_postgresql/connection.rb +17 -18
- data/test/connections/native_sqlite/connection.rb +17 -16
- data/test/connections/native_sqlite3/connection.rb +25 -0
- data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
- data/test/connections/native_sybase/connection.rb +23 -0
- data/test/copy_table_test_sqlite.rb +69 -0
- data/test/datatype_test_postgresql.rb +203 -0
- data/test/date_time_test.rb +37 -0
- data/test/default_test_firebird.rb +16 -0
- data/test/defaults_test.rb +67 -0
- data/test/deprecated_finder_test.rb +30 -0
- data/test/finder_test.rb +607 -32
- data/test/fixtures/accounts.yml +28 -0
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +107 -0
- data/test/fixtures/author_favorites.yml +4 -0
- data/test/fixtures/authors.yml +7 -0
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +1 -0
- data/test/fixtures/bad_fixtures/attr_with_spaces +1 -0
- data/test/fixtures/bad_fixtures/blank_line +3 -0
- data/test/fixtures/bad_fixtures/duplicate_attributes +3 -0
- data/test/fixtures/bad_fixtures/missing_value +1 -0
- data/test/fixtures/binaries.yml +132 -0
- data/test/fixtures/binary.rb +2 -0
- data/test/fixtures/book.rb +4 -0
- data/test/fixtures/books.yml +7 -0
- data/test/fixtures/categories/special_categories.yml +9 -0
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
- data/test/fixtures/categories.yml +14 -0
- data/test/fixtures/categories_ordered.yml +7 -0
- data/test/fixtures/categories_posts.yml +23 -0
- data/test/fixtures/categorization.rb +5 -0
- data/test/fixtures/categorizations.yml +17 -0
- data/test/fixtures/category.rb +26 -0
- data/test/fixtures/citation.rb +6 -0
- data/test/fixtures/comment.rb +23 -0
- data/test/fixtures/comments.yml +59 -0
- data/test/fixtures/companies.yml +55 -0
- data/test/fixtures/company.rb +81 -4
- data/test/fixtures/company_in_module.rb +32 -6
- data/test/fixtures/computer.rb +4 -0
- data/test/fixtures/computers.yml +4 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/courses.yml +7 -0
- data/test/fixtures/customer.rb +28 -3
- data/test/fixtures/customers.yml +17 -0
- data/test/fixtures/db_definitions/db2.drop.sql +33 -0
- data/test/fixtures/db_definitions/db2.sql +235 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +5 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +65 -0
- data/test/fixtures/db_definitions/firebird.sql +310 -0
- data/test/fixtures/db_definitions/firebird2.drop.sql +2 -0
- data/test/fixtures/db_definitions/firebird2.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +33 -0
- data/test/fixtures/db_definitions/frontbase.sql +273 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/openbase.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase.sql +318 -0
- data/test/fixtures/db_definitions/openbase2.drop.sql +2 -0
- data/test/fixtures/db_definitions/openbase2.sql +7 -0
- data/test/fixtures/db_definitions/oracle.drop.sql +67 -0
- data/test/fixtures/db_definitions/oracle.sql +330 -0
- data/test/fixtures/db_definitions/oracle2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +44 -0
- data/test/fixtures/db_definitions/postgresql.sql +217 -38
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +2 -2
- data/test/fixtures/db_definitions/schema.rb +354 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +33 -0
- data/test/fixtures/db_definitions/sqlite.sql +139 -5
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +1 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +35 -0
- data/test/fixtures/db_definitions/sybase.sql +222 -0
- data/test/fixtures/db_definitions/sybase2.drop.sql +4 -0
- data/test/fixtures/db_definitions/sybase2.sql +5 -0
- data/test/fixtures/developer.rb +70 -6
- data/test/fixtures/developers.yml +21 -0
- data/test/fixtures/developers_projects/david_action_controller +2 -1
- data/test/fixtures/developers_projects/david_active_record +2 -1
- data/test/fixtures/developers_projects.yml +17 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/entrants.yml +14 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/fk_test_has_fk.yml +3 -0
- data/test/fixtures/fk_test_has_pk.yml +2 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/funny_jokes.yml +10 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +3 -0
- data/test/fixtures/keyboard.rb +3 -0
- data/test/fixtures/legacy_thing.rb +3 -0
- data/test/fixtures/legacy_things.yml +3 -0
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/migrations/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_duplicate/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_duplicate/2_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_duplicate/3_foo.rb +7 -0
- data/test/fixtures/migrations_with_duplicate/3_innocent_jointable.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixed_case_monkey.rb +3 -0
- data/test/fixtures/mixed_case_monkeys.yml +6 -0
- data/test/fixtures/mixins.yml +29 -0
- data/test/fixtures/movies.yml +7 -0
- data/test/fixtures/naked/csv/accounts.csv +1 -0
- data/test/fixtures/naked/yml/accounts.yml +1 -0
- data/test/fixtures/naked/yml/companies.yml +1 -0
- data/test/fixtures/naked/yml/courses.yml +1 -0
- data/test/fixtures/order.rb +4 -0
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/people.yml +3 -0
- data/test/fixtures/person.rb +4 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +59 -0
- data/test/fixtures/posts.yml +48 -0
- data/test/fixtures/project.rb +27 -2
- data/test/fixtures/projects.yml +7 -0
- data/test/fixtures/reader.rb +4 -0
- data/test/fixtures/readers.yml +4 -0
- data/test/fixtures/reply.rb +18 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/subject.rb +4 -0
- data/test/fixtures/subscriber.rb +4 -3
- data/test/fixtures/tag.rb +7 -0
- data/test/fixtures/tagging.rb +10 -0
- data/test/fixtures/taggings.yml +25 -0
- data/test/fixtures/tags.yml +7 -0
- data/test/fixtures/task.rb +3 -0
- data/test/fixtures/tasks.yml +7 -0
- data/test/fixtures/topic.rb +20 -3
- data/test/fixtures/topics.yml +22 -0
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +574 -8
- data/test/inheritance_test.rb +113 -27
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +56 -29
- data/test/locking_test.rb +273 -0
- data/test/method_scoping_test.rb +416 -0
- data/test/migration_test.rb +933 -0
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_test.rb +95 -0
- data/test/modules_test.rb +23 -10
- data/test/multiple_db_test.rb +17 -3
- data/test/pk_test.rb +59 -15
- data/test/query_cache_test.rb +104 -0
- data/test/readonly_test.rb +107 -0
- data/test/reflection_test.rb +124 -27
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +131 -0
- data/test/schema_test_postgresql.rb +64 -0
- data/test/serialization_test.rb +47 -0
- data/test/synonym_test_oracle.rb +17 -0
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +48 -0
- data/test/transactions_test.rb +227 -29
- data/test/unconnected_test.rb +14 -6
- data/test/validations_test.rb +1293 -32
- data/test/xml_serialization_test.rb +202 -0
- metadata +347 -143
- data/dev-utils/eval_debugger.rb +0 -9
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -88
- data/lib/active_record/deprecated_associations.rb +0 -70
- data/lib/active_record/support/class_attribute_accessors.rb +0 -43
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/inflector.rb +0 -70
- data/lib/active_record/vendor/simple.rb +0 -702
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -59
- data/rakefile +0 -122
- data/test/deprecated_associations_test.rb +0 -336
- data/test/fixtures/accounts/signals37 +0 -3
- data/test/fixtures/accounts/unknown +0 -2
- data/test/fixtures/companies/first_client +0 -6
- data/test/fixtures/companies/first_firm +0 -4
- data/test/fixtures/companies/second_client +0 -6
- data/test/fixtures/courses/java +0 -2
- data/test/fixtures/courses/ruby +0 -2
- data/test/fixtures/customers/david +0 -6
- data/test/fixtures/db_definitions/mysql.sql +0 -96
- data/test/fixtures/db_definitions/mysql2.sql +0 -4
- data/test/fixtures/developers/david +0 -2
- data/test/fixtures/developers/jamis +0 -2
- data/test/fixtures/entrants/first +0 -3
- data/test/fixtures/entrants/second +0 -3
- data/test/fixtures/entrants/third +0 -3
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/movies/first +0 -2
- data/test/fixtures/movies/second +0 -2
- data/test/fixtures/projects/action_controller +0 -2
- data/test/fixtures/projects/active_record +0 -2
- data/test/fixtures/topics/first +0 -9
- data/test/fixtures/topics/second +0 -8
- data/test/inflector_test.rb +0 -104
- data/test/thread_safety_test.rb +0 -33
@@ -0,0 +1,362 @@
|
|
1
|
+
require 'db2/db2cli.rb'
|
2
|
+
|
3
|
+
module DB2
|
4
|
+
module DB2Util
|
5
|
+
include DB2CLI
|
6
|
+
|
7
|
+
def free() SQLFreeHandle(@handle_type, @handle); end
|
8
|
+
def handle() @handle; end
|
9
|
+
|
10
|
+
def check_rc(rc)
|
11
|
+
if ![SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA_FOUND].include?(rc)
|
12
|
+
rec = 1
|
13
|
+
msg = ''
|
14
|
+
loop do
|
15
|
+
a = SQLGetDiagRec(@handle_type, @handle, rec, 500)
|
16
|
+
break if a[0] != SQL_SUCCESS
|
17
|
+
msg << a[3] if !a[3].nil? and a[3] != '' # Create message.
|
18
|
+
rec += 1
|
19
|
+
end
|
20
|
+
raise "DB2 error: #{msg}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Environment
|
26
|
+
include DB2Util
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@handle_type = SQL_HANDLE_ENV
|
30
|
+
rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE)
|
31
|
+
check_rc(rc)
|
32
|
+
end
|
33
|
+
|
34
|
+
def data_sources(buffer_length = 1024)
|
35
|
+
retval = []
|
36
|
+
max_buffer_length = buffer_length
|
37
|
+
|
38
|
+
a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length)
|
39
|
+
retval << [a[1], a[3]]
|
40
|
+
max_buffer_length = [max_buffer_length, a[4]].max
|
41
|
+
|
42
|
+
loop do
|
43
|
+
a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length)
|
44
|
+
break if a[0] == SQL_NO_DATA_FOUND
|
45
|
+
|
46
|
+
retval << [a[1], a[3]]
|
47
|
+
max_buffer_length = [max_buffer_length, a[4]].max
|
48
|
+
end
|
49
|
+
|
50
|
+
if max_buffer_length > buffer_length
|
51
|
+
get_data_sources(max_buffer_length)
|
52
|
+
else
|
53
|
+
retval
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Connection
|
59
|
+
include DB2Util
|
60
|
+
|
61
|
+
def initialize(environment)
|
62
|
+
@env = environment
|
63
|
+
@handle_type = SQL_HANDLE_DBC
|
64
|
+
rc, @handle = SQLAllocHandle(@handle_type, @env.handle)
|
65
|
+
check_rc(rc)
|
66
|
+
end
|
67
|
+
|
68
|
+
def connect(server_name, user_name = '', auth = '')
|
69
|
+
check_rc(SQLConnect(@handle, server_name, user_name.to_s, auth.to_s))
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_connect_attr(attr, value)
|
73
|
+
value += "\0" if value.class == String
|
74
|
+
check_rc(SQLSetConnectAttr(@handle, attr, value))
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_auto_commit_on
|
78
|
+
set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_auto_commit_off
|
82
|
+
set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF)
|
83
|
+
end
|
84
|
+
|
85
|
+
def disconnect
|
86
|
+
check_rc(SQLDisconnect(@handle))
|
87
|
+
end
|
88
|
+
|
89
|
+
def rollback
|
90
|
+
check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK))
|
91
|
+
end
|
92
|
+
|
93
|
+
def commit
|
94
|
+
check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Statement
|
99
|
+
include DB2Util
|
100
|
+
|
101
|
+
def initialize(connection)
|
102
|
+
@conn = connection
|
103
|
+
@handle_type = SQL_HANDLE_STMT
|
104
|
+
@parms = [] #yun
|
105
|
+
@sql = '' #yun
|
106
|
+
@numParms = 0 #yun
|
107
|
+
@prepared = false #yun
|
108
|
+
@parmArray = [] #yun. attributes of the parameter markers
|
109
|
+
rc, @handle = SQLAllocHandle(@handle_type, @conn.handle)
|
110
|
+
check_rc(rc)
|
111
|
+
end
|
112
|
+
|
113
|
+
def columns(table_name, schema_name = '%')
|
114
|
+
check_rc(SQLColumns(@handle, '', schema_name.upcase, table_name.upcase, '%'))
|
115
|
+
fetch_all
|
116
|
+
end
|
117
|
+
|
118
|
+
def tables(schema_name = '%')
|
119
|
+
check_rc(SQLTables(@handle, '', schema_name.upcase, '%', 'TABLE'))
|
120
|
+
fetch_all
|
121
|
+
end
|
122
|
+
|
123
|
+
def indexes(table_name, schema_name = '')
|
124
|
+
check_rc(SQLStatistics(@handle, '', schema_name.upcase, table_name.upcase, SQL_INDEX_ALL, SQL_ENSURE))
|
125
|
+
fetch_all
|
126
|
+
end
|
127
|
+
|
128
|
+
def prepare(sql)
|
129
|
+
@sql = sql
|
130
|
+
check_rc(SQLPrepare(@handle, sql))
|
131
|
+
rc, @numParms = SQLNumParams(@handle) #number of question marks
|
132
|
+
check_rc(rc)
|
133
|
+
#--------------------------------------------------------------------------
|
134
|
+
# parameter attributes are stored in instance variable @parmArray so that
|
135
|
+
# they are available when execute method is called.
|
136
|
+
#--------------------------------------------------------------------------
|
137
|
+
if @numParms > 0 # get parameter marker attributes
|
138
|
+
1.upto(@numParms) do |i| # parameter number starts from 1
|
139
|
+
rc, type, size, decimalDigits = SQLDescribeParam(@handle, i)
|
140
|
+
check_rc(rc)
|
141
|
+
@parmArray << Parameter.new(type, size, decimalDigits)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
@prepared = true
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def execute(*parms)
|
149
|
+
raise "The statement was not prepared" if @prepared == false
|
150
|
+
|
151
|
+
if parms.size == 1 and parms[0].class == Array
|
152
|
+
parms = parms[0]
|
153
|
+
end
|
154
|
+
|
155
|
+
if @numParms != parms.size
|
156
|
+
raise "Number of parameters supplied does not match with the SQL statement"
|
157
|
+
end
|
158
|
+
|
159
|
+
if @numParms > 0 #need to bind parameters
|
160
|
+
#--------------------------------------------------------------------
|
161
|
+
#calling bindParms may not be safe. Look comment below.
|
162
|
+
#--------------------------------------------------------------------
|
163
|
+
#bindParms(parms)
|
164
|
+
|
165
|
+
valueArray = []
|
166
|
+
1.upto(@numParms) do |i| # parameter number starts from 1
|
167
|
+
type = @parmArray[i - 1].class
|
168
|
+
size = @parmArray[i - 1].size
|
169
|
+
decimalDigits = @parmArray[i - 1].decimalDigits
|
170
|
+
|
171
|
+
if parms[i - 1].class == String
|
172
|
+
valueArray << parms[i - 1]
|
173
|
+
else
|
174
|
+
valueArray << parms[i - 1].to_s
|
175
|
+
end
|
176
|
+
|
177
|
+
rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1])
|
178
|
+
check_rc(rc)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
check_rc(SQLExecute(@handle))
|
183
|
+
|
184
|
+
if @numParms != 0
|
185
|
+
check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters
|
186
|
+
end
|
187
|
+
|
188
|
+
self
|
189
|
+
end
|
190
|
+
|
191
|
+
#-------------------------------------------------------------------------------
|
192
|
+
# The last argument(value) to SQLBindParameter is a deferred argument, that is,
|
193
|
+
# it should be available when SQLExecute is called. Even though "value" is
|
194
|
+
# local to bindParms method, it seems that it is available when SQLExecute
|
195
|
+
# is called. I am not sure whether it would still work if garbage collection
|
196
|
+
# is done between bindParms call and SQLExecute call inside the execute method
|
197
|
+
# above.
|
198
|
+
#-------------------------------------------------------------------------------
|
199
|
+
def bindParms(parms) # This is the real thing. It uses SQLBindParms
|
200
|
+
1.upto(@numParms) do |i| # parameter number starts from 1
|
201
|
+
rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i)
|
202
|
+
check_rc(rc)
|
203
|
+
if parms[i - 1].class == String
|
204
|
+
value = parms[i - 1]
|
205
|
+
else
|
206
|
+
value = parms[i - 1].to_s
|
207
|
+
end
|
208
|
+
rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value)
|
209
|
+
check_rc(rc)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
#------------------------------------------------------------------------------
|
214
|
+
# bind method does not use DB2's SQLBindParams, but replaces "?" in the
|
215
|
+
# SQL statement with the value before passing the SQL statement to DB2.
|
216
|
+
# It is not efficient and can handle only strings since it puts everything in
|
217
|
+
# quotes.
|
218
|
+
#------------------------------------------------------------------------------
|
219
|
+
def bind(sql, args) #does not use SQLBindParams
|
220
|
+
arg_index = 0
|
221
|
+
result = ""
|
222
|
+
tokens(sql).each do |part|
|
223
|
+
case part
|
224
|
+
when '?'
|
225
|
+
result << "'" + (args[arg_index]) + "'" #put it into quotes
|
226
|
+
arg_index += 1
|
227
|
+
when '??'
|
228
|
+
result << "?"
|
229
|
+
else
|
230
|
+
result << part
|
231
|
+
end
|
232
|
+
end
|
233
|
+
if arg_index < args.size
|
234
|
+
raise "Too many SQL parameters"
|
235
|
+
elsif arg_index > args.size
|
236
|
+
raise "Not enough SQL parameters"
|
237
|
+
end
|
238
|
+
result
|
239
|
+
end
|
240
|
+
|
241
|
+
## Break the sql string into parts.
|
242
|
+
#
|
243
|
+
# This is NOT a full lexer for SQL. It just breaks up the SQL
|
244
|
+
# string enough so that question marks, double question marks and
|
245
|
+
# quoted strings are separated. This is used when binding
|
246
|
+
# arguments to "?" in the SQL string. Note: comments are not
|
247
|
+
# handled.
|
248
|
+
#
|
249
|
+
def tokens(sql)
|
250
|
+
toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/)
|
251
|
+
toks.collect { |t| t[0] }
|
252
|
+
end
|
253
|
+
|
254
|
+
def exec_direct(sql)
|
255
|
+
check_rc(SQLExecDirect(@handle, sql))
|
256
|
+
self
|
257
|
+
end
|
258
|
+
|
259
|
+
def set_cursor_name(name)
|
260
|
+
check_rc(SQLSetCursorName(@handle, name))
|
261
|
+
self
|
262
|
+
end
|
263
|
+
|
264
|
+
def get_cursor_name
|
265
|
+
rc, name = SQLGetCursorName(@handle)
|
266
|
+
check_rc(rc)
|
267
|
+
name
|
268
|
+
end
|
269
|
+
|
270
|
+
def row_count
|
271
|
+
rc, rowcount = SQLRowCount(@handle)
|
272
|
+
check_rc(rc)
|
273
|
+
rowcount
|
274
|
+
end
|
275
|
+
|
276
|
+
def num_result_cols
|
277
|
+
rc, cols = SQLNumResultCols(@handle)
|
278
|
+
check_rc(rc)
|
279
|
+
cols
|
280
|
+
end
|
281
|
+
|
282
|
+
def fetch_all
|
283
|
+
if block_given?
|
284
|
+
while row = fetch do
|
285
|
+
yield row
|
286
|
+
end
|
287
|
+
else
|
288
|
+
res = []
|
289
|
+
while row = fetch do
|
290
|
+
res << row
|
291
|
+
end
|
292
|
+
res
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
def fetch
|
297
|
+
cols = get_col_desc
|
298
|
+
rc = SQLFetch(@handle)
|
299
|
+
if rc == SQL_NO_DATA_FOUND
|
300
|
+
SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
|
301
|
+
SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
|
302
|
+
return nil
|
303
|
+
end
|
304
|
+
raise "ERROR" unless rc == SQL_SUCCESS
|
305
|
+
|
306
|
+
retval = []
|
307
|
+
cols.each_with_index do |c, i|
|
308
|
+
rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
|
309
|
+
retval << adjust_content(content)
|
310
|
+
end
|
311
|
+
retval
|
312
|
+
end
|
313
|
+
|
314
|
+
def fetch_as_hash
|
315
|
+
cols = get_col_desc
|
316
|
+
rc = SQLFetch(@handle)
|
317
|
+
if rc == SQL_NO_DATA_FOUND
|
318
|
+
SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
|
319
|
+
SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
|
320
|
+
return nil
|
321
|
+
end
|
322
|
+
raise "ERROR" unless rc == SQL_SUCCESS
|
323
|
+
|
324
|
+
retval = {}
|
325
|
+
cols.each_with_index do |c, i|
|
326
|
+
rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
|
327
|
+
retval[c[0]] = adjust_content(content)
|
328
|
+
end
|
329
|
+
retval
|
330
|
+
end
|
331
|
+
|
332
|
+
def get_col_desc
|
333
|
+
rc, nr_cols = SQLNumResultCols(@handle)
|
334
|
+
cols = (1..nr_cols).collect do |c|
|
335
|
+
rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024)
|
336
|
+
[name.downcase, type, col_sz]
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def adjust_content(c)
|
341
|
+
case c.class.to_s
|
342
|
+
when 'DB2CLI::NullClass'
|
343
|
+
return nil
|
344
|
+
when 'DB2CLI::Time'
|
345
|
+
"%02d:%02d:%02d" % [c.hour, c.minute, c.second]
|
346
|
+
when 'DB2CLI::Date'
|
347
|
+
"%04d-%02d-%02d" % [c.year, c.month, c.day]
|
348
|
+
when 'DB2CLI::Timestamp'
|
349
|
+
"%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second]
|
350
|
+
else
|
351
|
+
return c
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
class Parameter
|
357
|
+
attr_reader :type, :size, :decimalDigits
|
358
|
+
def initialize(type, size, decimalDigits)
|
359
|
+
@type, @size, @decimalDigits = type, size, decimalDigits
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
@@ -1,14 +1,15 @@
|
|
1
|
-
# $Id: mysql.rb,v 1.
|
1
|
+
# $Id: mysql.rb,v 1.24 2005/02/12 11:37:15 tommy Exp $
|
2
2
|
#
|
3
|
-
# Copyright (C) 2003 TOMITA Masahiro
|
3
|
+
# Copyright (C) 2003-2005 TOMITA Masahiro
|
4
4
|
# tommy@tmtm.org
|
5
5
|
#
|
6
6
|
|
7
7
|
class Mysql
|
8
8
|
|
9
|
-
VERSION = "4.0-ruby-0.2.
|
9
|
+
VERSION = "4.0-ruby-0.2.6-plus-changes"
|
10
10
|
|
11
11
|
require "socket"
|
12
|
+
require "digest/sha1"
|
12
13
|
|
13
14
|
MAX_PACKET_LENGTH = 256*256*256-1
|
14
15
|
MAX_ALLOWED_PACKET = 1024*1024*1024
|
@@ -17,6 +18,9 @@ class Mysql
|
|
17
18
|
MYSQL_PORT = 3306
|
18
19
|
PROTOCOL_VERSION = 10
|
19
20
|
|
21
|
+
SCRAMBLE_LENGTH = 20
|
22
|
+
SCRAMBLE_LENGTH_323 = 8
|
23
|
+
|
20
24
|
# Command
|
21
25
|
COM_SLEEP = 0
|
22
26
|
COM_QUIT = 1
|
@@ -51,11 +55,15 @@ class Mysql
|
|
51
55
|
CLIENT_ODBC = 1 << 6
|
52
56
|
CLIENT_LOCAL_FILES = 1 << 7
|
53
57
|
CLIENT_IGNORE_SPACE = 1 << 8
|
58
|
+
CLIENT_PROTOCOL_41 = 1 << 9
|
54
59
|
CLIENT_INTERACTIVE = 1 << 10
|
55
60
|
CLIENT_SSL = 1 << 11
|
56
61
|
CLIENT_IGNORE_SIGPIPE = 1 << 12
|
57
62
|
CLIENT_TRANSACTIONS = 1 << 13
|
63
|
+
CLIENT_RESERVED = 1 << 14
|
64
|
+
CLIENT_SECURE_CONNECTION = 1 << 15
|
58
65
|
CLIENT_CAPABILITIES = CLIENT_LONG_PASSWORD|CLIENT_LONG_FLAG|CLIENT_TRANSACTIONS
|
66
|
+
PROTO_AUTH41 = CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION
|
59
67
|
|
60
68
|
# Connection Option
|
61
69
|
OPT_CONNECT_TIMEOUT = 0
|
@@ -115,23 +123,50 @@ class Mysql
|
|
115
123
|
@server_capabilities, = a.slice!(0,2).unpack("v")
|
116
124
|
end
|
117
125
|
if a.size >= 16 then
|
118
|
-
@server_language, @server_status = a.unpack("cv")
|
126
|
+
@server_language, @server_status = a.slice!(0,3).unpack("cv")
|
119
127
|
end
|
120
128
|
|
121
129
|
flag = 0 if flag == nil
|
122
130
|
flag |= @client_flag | CLIENT_CAPABILITIES
|
123
131
|
flag |= CLIENT_CONNECT_WITH_DB if db
|
124
|
-
|
125
|
-
|
126
|
-
|
132
|
+
|
133
|
+
@pre_411 = (0 == @server_capabilities & PROTO_AUTH41)
|
134
|
+
if @pre_411
|
135
|
+
data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+
|
136
|
+
(user||"")+"\0"+
|
137
|
+
scramble(passwd, @scramble_buff, @protocol_version==9)
|
138
|
+
else
|
139
|
+
dummy, @salt2 = a.unpack("a13a12")
|
140
|
+
@scramble_buff += @salt2
|
141
|
+
flag |= PROTO_AUTH41
|
142
|
+
data = Net::int4str(flag) + Net::int4str(@max_allowed_packet) +
|
143
|
+
([8] + Array.new(23, 0)).pack("c24") + (user||"")+"\0"+
|
144
|
+
scramble41(passwd, @scramble_buff)
|
145
|
+
end
|
146
|
+
|
147
|
+
if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
|
148
|
+
data << "\0" if @pre_411
|
149
|
+
data << db
|
127
150
|
@db = db.dup
|
128
151
|
end
|
129
152
|
write data
|
130
|
-
read
|
153
|
+
pkt = read
|
154
|
+
handle_auth_fallback(pkt, passwd)
|
155
|
+
ObjectSpace.define_finalizer(self, Mysql.finalizer(@net))
|
131
156
|
self
|
132
157
|
end
|
133
158
|
alias :connect :real_connect
|
134
159
|
|
160
|
+
def handle_auth_fallback(pkt, passwd)
|
161
|
+
# A packet like this means that we need to send an old-format password
|
162
|
+
if pkt.size == 1 and pkt[0] == 254 and
|
163
|
+
@server_capabilities & CLIENT_SECURE_CONNECTION != 0 then
|
164
|
+
data = scramble(passwd, @scramble_buff, @protocol_version == 9)
|
165
|
+
write data + "\0"
|
166
|
+
read
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
135
170
|
def escape_string(str)
|
136
171
|
Mysql::escape_string str
|
137
172
|
end
|
@@ -182,8 +217,13 @@ class Mysql
|
|
182
217
|
end
|
183
218
|
|
184
219
|
def change_user(user="", passwd="", db="")
|
185
|
-
|
186
|
-
|
220
|
+
if @pre_411
|
221
|
+
data = user+"\0"+scramble(passwd, @scramble_buff, @protocol_version==9)+"\0"+db
|
222
|
+
else
|
223
|
+
data = user+"\0"+scramble41(passwd, @scramble_buff)+db
|
224
|
+
end
|
225
|
+
pkt = command COM_CHANGE_USER, data
|
226
|
+
handle_auth_fallback(pkt, passwd)
|
187
227
|
@user = user
|
188
228
|
@passwd = passwd
|
189
229
|
@db = db
|
@@ -243,7 +283,11 @@ class Mysql
|
|
243
283
|
|
244
284
|
def list_fields(table, field=nil)
|
245
285
|
command COM_FIELD_LIST, "#{table}\0#{field}", true
|
246
|
-
|
286
|
+
if @pre_411
|
287
|
+
f = read_rows 6
|
288
|
+
else
|
289
|
+
f = read_rows 7
|
290
|
+
end
|
247
291
|
fields = unpack_fields(f, @server_capabilities & CLIENT_LONG_FLAG != 0)
|
248
292
|
res = Result::new self, fields, f.length
|
249
293
|
res.eof = true
|
@@ -253,7 +297,11 @@ class Mysql
|
|
253
297
|
def list_processes()
|
254
298
|
data = command COM_PROCESS_INFO
|
255
299
|
@field_count = get_length data
|
256
|
-
|
300
|
+
if @pre_411
|
301
|
+
fields = read_rows 5
|
302
|
+
else
|
303
|
+
fields = read_rows 7
|
304
|
+
end
|
257
305
|
@fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
|
258
306
|
@status = :STATUS_GET_RESULT
|
259
307
|
store_result
|
@@ -311,7 +359,11 @@ class Mysql
|
|
311
359
|
|
312
360
|
def read_one_row(field_count)
|
313
361
|
data = read
|
314
|
-
|
362
|
+
if data[0] == 254 and data.length == 1 ## EOF
|
363
|
+
return
|
364
|
+
elsif data[0] == 254 and data.length == 5
|
365
|
+
return
|
366
|
+
end
|
315
367
|
rec = []
|
316
368
|
field_count.times do
|
317
369
|
len = get_length data
|
@@ -363,7 +415,11 @@ class Mysql
|
|
363
415
|
end
|
364
416
|
else
|
365
417
|
@extra_info = get_length(data, true)
|
366
|
-
|
418
|
+
if @pre_411
|
419
|
+
fields = read_rows(5)
|
420
|
+
else
|
421
|
+
fields = read_rows(7)
|
422
|
+
end
|
367
423
|
@fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
|
368
424
|
@status = :STATUS_GET_RESULT
|
369
425
|
end
|
@@ -373,19 +429,34 @@ class Mysql
|
|
373
429
|
def unpack_fields(data, long_flag_protocol)
|
374
430
|
ret = []
|
375
431
|
data.each do |f|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
432
|
+
if @pre_411
|
433
|
+
table = org_table = f[0]
|
434
|
+
name = f[1]
|
435
|
+
length = f[2][0]+f[2][1]*256+f[2][2]*256*256
|
436
|
+
type = f[3][0]
|
437
|
+
if long_flag_protocol then
|
438
|
+
flags = f[4][0]+f[4][1]*256
|
439
|
+
decimals = f[4][2]
|
440
|
+
else
|
441
|
+
flags = f[4][0]
|
442
|
+
decimals = f[4][1]
|
443
|
+
end
|
444
|
+
def_value = f[5]
|
445
|
+
max_length = 0
|
383
446
|
else
|
384
|
-
|
385
|
-
|
447
|
+
catalog = f[0]
|
448
|
+
db = f[1]
|
449
|
+
table = f[2]
|
450
|
+
org_table = f[3]
|
451
|
+
name = f[4]
|
452
|
+
org_name = f[5]
|
453
|
+
length = f[6][2]+f[6][3]*256+f[6][4]*256*256
|
454
|
+
type = f[6][6]
|
455
|
+
flags = f[6][7]+f[6][8]*256
|
456
|
+
decimals = f[6][9]
|
457
|
+
def_value = ""
|
458
|
+
max_length = 0
|
386
459
|
end
|
387
|
-
def_value = f[5]
|
388
|
-
max_length = 0
|
389
460
|
ret << Field::new(table, org_table, name, length, type, flags, decimals, def_value, max_length)
|
390
461
|
end
|
391
462
|
ret
|
@@ -478,10 +549,10 @@ class Mysql
|
|
478
549
|
return "" if password == nil or password == ""
|
479
550
|
raise "old version password is not implemented" if old_ver
|
480
551
|
hash_pass = hash_password password
|
481
|
-
hash_message = hash_password message
|
552
|
+
hash_message = hash_password message.slice(0,SCRAMBLE_LENGTH_323)
|
482
553
|
rnd = Random::new hash_pass[0] ^ hash_message[0], hash_pass[1] ^ hash_message[1]
|
483
554
|
to = []
|
484
|
-
1.upto(
|
555
|
+
1.upto(SCRAMBLE_LENGTH_323) do
|
485
556
|
to << ((rnd.rnd*31)+64).floor
|
486
557
|
end
|
487
558
|
extra = (rnd.rnd*31).floor
|
@@ -489,6 +560,16 @@ class Mysql
|
|
489
560
|
to.join
|
490
561
|
end
|
491
562
|
|
563
|
+
def scramble41(password, message)
|
564
|
+
return 0x00.chr if password.nil? or password.empty?
|
565
|
+
buf = [0x14]
|
566
|
+
s1 = Digest::SHA1.digest(password)
|
567
|
+
s2 = Digest::SHA1.digest(s1)
|
568
|
+
x = Digest::SHA1.digest(message + s2)
|
569
|
+
(0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
|
570
|
+
buf.pack("C*")
|
571
|
+
end
|
572
|
+
|
492
573
|
def error(errno)
|
493
574
|
@errno = errno
|
494
575
|
@error = Error::err errno
|
@@ -574,7 +655,6 @@ class Mysql
|
|
574
655
|
def free()
|
575
656
|
@handle.skip_result
|
576
657
|
@handle = @fields = @data = nil
|
577
|
-
GC::start
|
578
658
|
end
|
579
659
|
|
580
660
|
def num_fields()
|
@@ -1022,6 +1102,9 @@ class Mysql
|
|
1022
1102
|
end
|
1023
1103
|
@sock.sync = true
|
1024
1104
|
buf.join
|
1105
|
+
rescue
|
1106
|
+
errno = Error::CR_SERVER_LOST
|
1107
|
+
raise Error::new(errno, Error::err(errno))
|
1025
1108
|
end
|
1026
1109
|
|
1027
1110
|
def write(data)
|
@@ -1039,6 +1122,9 @@ class Mysql
|
|
1039
1122
|
@pkt_nr = @pkt_nr + 1 & 0xff
|
1040
1123
|
@sock.sync = true
|
1041
1124
|
@sock.flush
|
1125
|
+
rescue
|
1126
|
+
errno = Error::CR_SERVER_LOST
|
1127
|
+
raise Error::new(errno, Error::err(errno))
|
1042
1128
|
end
|
1043
1129
|
|
1044
1130
|
def close()
|
@@ -1085,13 +1171,24 @@ class << Mysql
|
|
1085
1171
|
end
|
1086
1172
|
alias :connect :real_connect
|
1087
1173
|
|
1174
|
+
def finalizer(net)
|
1175
|
+
proc {
|
1176
|
+
net.clear
|
1177
|
+
begin
|
1178
|
+
net.write(Mysql::COM_QUIT.chr)
|
1179
|
+
net.close
|
1180
|
+
rescue # Ignore IOError if socket is already closed.
|
1181
|
+
end
|
1182
|
+
}
|
1183
|
+
end
|
1184
|
+
|
1088
1185
|
def escape_string(str)
|
1089
1186
|
str.gsub(/([\0\n\r\032\'\"\\])/) do
|
1090
1187
|
case $1
|
1091
1188
|
when "\0" then "\\0"
|
1092
1189
|
when "\n" then "\\n"
|
1093
1190
|
when "\r" then "\\r"
|
1094
|
-
when "\032" then "
|
1191
|
+
when "\032" then "\\Z"
|
1095
1192
|
else "\\"+$1
|
1096
1193
|
end
|
1097
1194
|
end
|