ydbi 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/ChangeLog +3699 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/Rakefile +8 -0
  7. data/TODO +44 -0
  8. data/bench/bench.rb +79 -0
  9. data/bin/dbi +518 -0
  10. data/bin/test_broken_dbi +37 -0
  11. data/build/Rakefile.dbi.rb +60 -0
  12. data/build/rake_task_lib.rb +187 -0
  13. data/doc/DBD_SPEC.rdoc +88 -0
  14. data/doc/DBI_SPEC.rdoc +157 -0
  15. data/doc/homepage/contact.html +62 -0
  16. data/doc/homepage/development.html +124 -0
  17. data/doc/homepage/index.html +83 -0
  18. data/doc/homepage/ruby-dbi.css +91 -0
  19. data/examples/test1.pl +39 -0
  20. data/examples/test1.rb +20 -0
  21. data/examples/xmltest.rb +8 -0
  22. data/lib/dbd/Mysql.rb +137 -0
  23. data/lib/dbd/ODBC.rb +89 -0
  24. data/lib/dbd/Pg.rb +188 -0
  25. data/lib/dbd/SQLite.rb +97 -0
  26. data/lib/dbd/SQLite3.rb +124 -0
  27. data/lib/dbd/mysql/database.rb +405 -0
  28. data/lib/dbd/mysql/driver.rb +125 -0
  29. data/lib/dbd/mysql/statement.rb +188 -0
  30. data/lib/dbd/odbc/database.rb +128 -0
  31. data/lib/dbd/odbc/driver.rb +38 -0
  32. data/lib/dbd/odbc/statement.rb +137 -0
  33. data/lib/dbd/pg/database.rb +516 -0
  34. data/lib/dbd/pg/exec.rb +47 -0
  35. data/lib/dbd/pg/statement.rb +160 -0
  36. data/lib/dbd/pg/tuples.rb +121 -0
  37. data/lib/dbd/pg/type.rb +209 -0
  38. data/lib/dbd/sqlite/database.rb +151 -0
  39. data/lib/dbd/sqlite/statement.rb +125 -0
  40. data/lib/dbd/sqlite3/database.rb +201 -0
  41. data/lib/dbd/sqlite3/statement.rb +78 -0
  42. data/lib/dbi.rb +336 -0
  43. data/lib/dbi/base_classes.rb +12 -0
  44. data/lib/dbi/base_classes/database.rb +135 -0
  45. data/lib/dbi/base_classes/driver.rb +47 -0
  46. data/lib/dbi/base_classes/statement.rb +171 -0
  47. data/lib/dbi/binary.rb +25 -0
  48. data/lib/dbi/columninfo.rb +107 -0
  49. data/lib/dbi/exceptions.rb +65 -0
  50. data/lib/dbi/handles.rb +49 -0
  51. data/lib/dbi/handles/database.rb +241 -0
  52. data/lib/dbi/handles/driver.rb +60 -0
  53. data/lib/dbi/handles/statement.rb +408 -0
  54. data/lib/dbi/row.rb +269 -0
  55. data/lib/dbi/sql.rb +22 -0
  56. data/lib/dbi/sql/preparedstatement.rb +115 -0
  57. data/lib/dbi/sql_type_constants.rb +75 -0
  58. data/lib/dbi/trace.rb +91 -0
  59. data/lib/dbi/types.rb +218 -0
  60. data/lib/dbi/typeutil.rb +109 -0
  61. data/lib/dbi/utils.rb +60 -0
  62. data/lib/dbi/utils/date.rb +59 -0
  63. data/lib/dbi/utils/tableformatter.rb +112 -0
  64. data/lib/dbi/utils/time.rb +52 -0
  65. data/lib/dbi/utils/timestamp.rb +96 -0
  66. data/lib/dbi/utils/xmlformatter.rb +73 -0
  67. data/lib/dbi/version.rb +3 -0
  68. data/prototypes/types2.rb +237 -0
  69. data/readme.md +274 -0
  70. data/setup.rb +1585 -0
  71. data/test/DBD_TESTS +50 -0
  72. data/test/TESTING +16 -0
  73. data/test/dbd/general/test_database.rb +206 -0
  74. data/test/dbd/general/test_statement.rb +326 -0
  75. data/test/dbd/general/test_types.rb +296 -0
  76. data/test/dbd/mysql/base.rb +26 -0
  77. data/test/dbd/mysql/down.sql +19 -0
  78. data/test/dbd/mysql/test_blob.rb +18 -0
  79. data/test/dbd/mysql/test_new_methods.rb +7 -0
  80. data/test/dbd/mysql/test_patches.rb +111 -0
  81. data/test/dbd/mysql/up.sql +28 -0
  82. data/test/dbd/odbc/base.rb +30 -0
  83. data/test/dbd/odbc/down.sql +19 -0
  84. data/test/dbd/odbc/test_new_methods.rb +12 -0
  85. data/test/dbd/odbc/test_ping.rb +10 -0
  86. data/test/dbd/odbc/test_statement.rb +44 -0
  87. data/test/dbd/odbc/test_transactions.rb +58 -0
  88. data/test/dbd/odbc/up.sql +33 -0
  89. data/test/dbd/postgresql/base.rb +31 -0
  90. data/test/dbd/postgresql/down.sql +31 -0
  91. data/test/dbd/postgresql/test_arrays.rb +179 -0
  92. data/test/dbd/postgresql/test_async.rb +121 -0
  93. data/test/dbd/postgresql/test_blob.rb +36 -0
  94. data/test/dbd/postgresql/test_bytea.rb +87 -0
  95. data/test/dbd/postgresql/test_ping.rb +10 -0
  96. data/test/dbd/postgresql/test_timestamp.rb +77 -0
  97. data/test/dbd/postgresql/test_transactions.rb +58 -0
  98. data/test/dbd/postgresql/testdbipg.rb +307 -0
  99. data/test/dbd/postgresql/up.sql +60 -0
  100. data/test/dbd/sqlite/base.rb +32 -0
  101. data/test/dbd/sqlite/test_database.rb +30 -0
  102. data/test/dbd/sqlite/test_driver.rb +68 -0
  103. data/test/dbd/sqlite/test_statement.rb +112 -0
  104. data/test/dbd/sqlite/up.sql +25 -0
  105. data/test/dbd/sqlite3/base.rb +32 -0
  106. data/test/dbd/sqlite3/test_database.rb +77 -0
  107. data/test/dbd/sqlite3/test_driver.rb +67 -0
  108. data/test/dbd/sqlite3/test_statement.rb +88 -0
  109. data/test/dbd/sqlite3/up.sql +33 -0
  110. data/test/dbi/tc_columninfo.rb +94 -0
  111. data/test/dbi/tc_date.rb +88 -0
  112. data/test/dbi/tc_dbi.rb +184 -0
  113. data/test/dbi/tc_row.rb +256 -0
  114. data/test/dbi/tc_sqlbind.rb +168 -0
  115. data/test/dbi/tc_statementhandle.rb +29 -0
  116. data/test/dbi/tc_time.rb +77 -0
  117. data/test/dbi/tc_timestamp.rb +142 -0
  118. data/test/dbi/tc_types.rb +268 -0
  119. data/test/ts_dbd.rb +131 -0
  120. data/test/ts_dbi.rb +16 -0
  121. data/ydbi.gemspec +24 -0
  122. metadata +224 -0
@@ -0,0 +1,28 @@
1
+ create table names (
2
+ name varchar(255),
3
+ age integer
4
+ ) Engine=InnoDB;
5
+ ---
6
+ insert into names (name, age) values ('Joe', 19);
7
+ ---
8
+ insert into names (name, age) values ('Jim', 30);
9
+ ---
10
+ insert into names (name, age) values ('Bob', 21);
11
+ ---
12
+ create table precision_test (text_field varchar(20) primary key not null, integer_field integer, decimal_field decimal(2,1), numeric_field numeric(30,6));
13
+ ---
14
+ CREATE TABLE blob_test (name VARCHAR(30), data BLOB) Engine=InnoDB;
15
+ ---
16
+ create view view_names as select * from names;
17
+ ---
18
+ create table boolean_test (num integer, mybool boolean) Engine=InnoDB;
19
+ ---
20
+ create table time_test (mytime time) Engine=InnoDB;
21
+ ---
22
+ create table timestamp_test (mytimestamp timestamp) Engine=InnoDB;
23
+ ---
24
+ create table bit_test (mybit bit) Engine=InnoDB;
25
+ ---
26
+ create table field_types_test (foo integer not null primary key default 1);
27
+ ---
28
+ create table db_specific_types_test (ts timestamp, dt date);
@@ -0,0 +1,30 @@
1
+ require 'fileutils'
2
+
3
+ DBDConfig.set_testbase(:odbc, Class.new(Test::Unit::TestCase) do
4
+
5
+ def dbtype
6
+ "odbc"
7
+ end
8
+
9
+ def test_base
10
+ assert_equal(@dbh.driver_name, "odbc")
11
+ assert_kind_of(DBI::DBD::ODBC::Database, @dbh.instance_variable_get(:@handle))
12
+ end
13
+
14
+ def set_base_dbh
15
+ config = DBDConfig.get_config['odbc']
16
+ @dbh = DBI.connect("dbi:ODBC:#{config['dbname']}", config['username'], config['password'])
17
+ end
18
+
19
+ def setup
20
+ set_base_dbh
21
+ DBDConfig.inject_sql(@dbh, dbtype, "dbd/odbc/up.sql")
22
+ end
23
+
24
+ def teardown
25
+ @sth.finish if @sth && !@sth.finished?
26
+ DBDConfig.inject_sql(@dbh, dbtype, "dbd/odbc/down.sql")
27
+ @dbh.disconnect
28
+ end
29
+ end
30
+ )
@@ -0,0 +1,19 @@
1
+ drop view view_names;
2
+ ---
3
+ drop table names;
4
+ ---
5
+ drop table blob_test;
6
+ ---
7
+ drop table boolean_test;
8
+ ---
9
+ drop table time_test;
10
+ ---
11
+ drop table timestamp_test;
12
+ ---
13
+ drop table bit_test;
14
+ ---
15
+ drop table field_types_test;
16
+ ---
17
+ drop table db_specific_types_test;
18
+ ---
19
+ drop table precision_test;
@@ -0,0 +1,12 @@
1
+ class TestODBCPing < DBDConfig.testbase(:odbc)
2
+ def test_database_name
3
+ #
4
+ # NOTE this test will fail if the database is not named "rubytest". I
5
+ # don't think there's a good way to get around this, so I've set it to
6
+ # what I typically use in my odbc.ini. - erikh
7
+ #
8
+ assert_nothing_raised do
9
+ assert_equal "rubytest", @dbh.database_name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ class TestODBCPing < DBDConfig.testbase(:odbc)
2
+ def test_ping
3
+ config = DBDConfig.get_config['odbc']
4
+ dbh = DBI.connect("dbi:ODBC:#{config['dbname']}", config['username'], config['password'])
5
+ assert dbh
6
+ assert dbh.ping
7
+ dbh.disconnect
8
+ assert_raises(DBI::InterfaceError) { dbh.ping }
9
+ end
10
+ end
@@ -0,0 +1,44 @@
1
+ class TestODBCStatement < DBDConfig.testbase(:odbc)
2
+ def test_column_info
3
+ sth = nil
4
+
5
+ assert_nothing_raised do
6
+ sth = @dbh.prepare("select * from names")
7
+ sth.execute
8
+ end
9
+
10
+ assert_kind_of Array, sth.column_info
11
+ assert_kind_of DBI::ColumnInfo, sth.column_info[0]
12
+ assert_kind_of DBI::ColumnInfo, sth.column_info[1]
13
+ # XXX odbc seems to have a problem with this every other edition of unixodbc or so.
14
+ # yes, I know this test is important.
15
+ # assert_equal [
16
+ # {
17
+ # :table=>"names",
18
+ # :precision=>255,
19
+ # :searchable=>true,
20
+ # :name=>"name",
21
+ # :unsigned=>true,
22
+ # :length=>255,
23
+ # :sql_type=>12,
24
+ # :scale=>0,
25
+ # :nullable=>true,
26
+ # :type_name=>"VARCHAR"
27
+ # },
28
+ # {
29
+ # :table=>"names",
30
+ # :precision=>10,
31
+ # :searchable=>true,
32
+ # :name=>"age",
33
+ # :unsigned=>false,
34
+ # :length=>4,
35
+ # :sql_type=>4,
36
+ # :scale=>0,
37
+ # :nullable=>true,
38
+ # :type_name=>"INTEGER"
39
+ # }
40
+ # ], sth.column_info
41
+
42
+ sth.finish
43
+ end
44
+ end
@@ -0,0 +1,58 @@
1
+ class TestODBCTransaction < DBDConfig.testbase(:odbc)
2
+ def test_rollback
3
+ dbh = get_dbh
4
+ dbh["AutoCommit"] = false
5
+ @sth = dbh.prepare('insert into names (name, age) values (?, ?)')
6
+ @sth.execute("Foo", 51)
7
+ dbh.rollback
8
+ assert_equal 1, @sth.rows
9
+ @sth.finish
10
+
11
+
12
+ @sth = dbh.prepare('select name, age from names where name=?')
13
+ @sth.execute("Foo")
14
+ assert !@sth.fetch
15
+ @sth.finish
16
+ dbh.disconnect
17
+ end
18
+
19
+ def test_commit
20
+ dbh = get_dbh
21
+ dbh["AutoCommit"] = false
22
+ @sth = dbh.prepare('insert into names (name, age) values (?, ?)')
23
+ @sth.execute("Foo", 51)
24
+ dbh.commit
25
+ assert_equal 1, @sth.rows
26
+ @sth.finish
27
+
28
+ @sth = dbh.prepare('select name, age from names where name=?')
29
+ @sth.execute("Foo")
30
+ row = @sth.fetch
31
+ assert row
32
+ assert_equal "Foo", row[0]
33
+ assert_equal 51, row[1]
34
+ @sth.finish
35
+ dbh.disconnect
36
+ end
37
+
38
+ def test_select_transaction
39
+ # per bug #10466
40
+ dbh = get_dbh
41
+ dbh["AutoCommit"] = false
42
+ @sth = dbh.prepare('select * from test_insert(?, ?)');
43
+ @sth.execute("Foo", 51)
44
+ dbh.rollback
45
+ @sth.finish
46
+
47
+ @sth = dbh.prepare('select name, age from names where name=?')
48
+ @sth.execute("Foo")
49
+ assert !@sth.fetch
50
+ @sth.finish
51
+ dbh.disconnect
52
+ end
53
+
54
+ def get_dbh
55
+ config = DBDConfig.get_config['odbc']
56
+ DBI.connect("dbi:ODBC:#{config['dbname']}", config['username'], config['password'])
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ create table names (
2
+ name varchar(255),
3
+ age integer
4
+ );
5
+ ---
6
+ insert into names (name, age) values ('Joe', 19);
7
+ ---
8
+ insert into names (name, age) values ('Jim', 30);
9
+ ---
10
+ insert into names (name, age) values ('Bob', 21);
11
+ ---
12
+ create table precision_test (text_field varchar(20) primary key not null, integer_field integer, decimal_field decimal(2,1), numeric_field numeric(30,6));
13
+ ---
14
+ CREATE TABLE blob_test (name VARCHAR(30), data OID);
15
+ ---
16
+ create view view_names as select * from names;
17
+ ---
18
+ create or replace function test_insert (varchar(255), integer)
19
+ returns integer
20
+ language sql
21
+ as 'insert into names (name, age) values ($1, $2); select age from names where name = $1';
22
+ ---
23
+ create table boolean_test (num integer, mybool boolean);
24
+ ---
25
+ create table time_test (mytime time);
26
+ ---
27
+ create table timestamp_test (mytimestamp timestamp);
28
+ ---
29
+ create table bit_test (mybit bit);
30
+ ---
31
+ create table field_types_test (foo integer not null primary key default 1);
32
+ ---
33
+ create table db_specific_types_test (foo integer);
@@ -0,0 +1,31 @@
1
+ require 'fileutils'
2
+
3
+ DBDConfig.set_testbase(:postgresql, Class.new(Test::Unit::TestCase) do
4
+
5
+ def dbtype
6
+ "postgresql"
7
+ end
8
+
9
+ def test_base
10
+ assert_equal(@dbh.driver_name, "Pg")
11
+ assert_kind_of(DBI::DBD::Pg::Database, @dbh.instance_variable_get(:@handle))
12
+ end
13
+
14
+ def set_base_dbh
15
+ config = DBDConfig.get_config['postgresql']
16
+ @dbh = DBI.connect("dbi:Pg:#{config['dbname']}", config['username'], config['password'])
17
+ end
18
+
19
+ def setup
20
+ set_base_dbh
21
+ DBDConfig.inject_sql(@dbh, dbtype, "dbd/postgresql/up.sql")
22
+ end
23
+
24
+ def teardown
25
+ @sth.finish if @sth && !@sth.finished?
26
+ config = DBDConfig.get_config['postgresql']
27
+ DBDConfig.inject_sql(@dbh, dbtype, "dbd/postgresql/down.sql")
28
+ @dbh.disconnect
29
+ end
30
+ end
31
+ )
@@ -0,0 +1,31 @@
1
+ drop view view_names;
2
+ ---
3
+ drop table names;
4
+ ---
5
+ drop table blob_test;
6
+ ---
7
+ drop table boolean_test;
8
+ ---
9
+ drop table time_test;
10
+ ---
11
+ drop table timestamp_test;
12
+ ---
13
+ drop table bit_test;
14
+ ---
15
+ drop table field_types_test;
16
+ ---
17
+ drop table db_specific_types_test;
18
+ ---
19
+ drop table array_test;
20
+ ---
21
+ drop table bytea_test;
22
+ ---
23
+ drop table precision_test;
24
+ ---
25
+ drop table enum_type_test;
26
+ ---
27
+ drop type enum_test;
28
+ ---
29
+ drop schema schema1 cascade;
30
+ ---
31
+ drop schema schema2 cascade;
@@ -0,0 +1,179 @@
1
+ class TestPostgresArray < DBDConfig.testbase(:postgresql)
2
+ def test_array_type
3
+ assert_nothing_raised do
4
+ cols = @dbh.columns("array_test")
5
+ assert_equal(
6
+ [
7
+ {
8
+ :name =>"foo",
9
+ :default =>nil,
10
+ :primary =>nil,
11
+ :scale =>nil,
12
+ :sql_type =>DBI::SQL_INTEGER,
13
+ :nullable =>true,
14
+ :indexed =>false,
15
+ :precision =>-1,
16
+ :type_name =>"integer",
17
+ :unique =>nil,
18
+ :array_of_type => true
19
+ },
20
+ {
21
+ :name =>"bar",
22
+ :default =>nil,
23
+ :primary =>nil,
24
+ :scale =>nil,
25
+ :sql_type =>DBI::SQL_INTEGER,
26
+ :nullable =>true,
27
+ :indexed =>false,
28
+ :precision =>-1,
29
+ :type_name =>"integer",
30
+ :unique =>nil,
31
+ :array_of_type => true
32
+ },
33
+ {
34
+ :name =>"baz",
35
+ :default =>nil,
36
+ :primary =>nil,
37
+ :scale =>nil,
38
+ :sql_type =>DBI::SQL_INTEGER,
39
+ :nullable =>true,
40
+ :indexed =>false,
41
+ :precision =>-1,
42
+ :type_name =>"integer",
43
+ :unique =>nil,
44
+ :array_of_type => true
45
+ },
46
+ {
47
+ :array_of_type=>true,
48
+ :unique=>nil,
49
+ :precision=>-1,
50
+ :name=>"quux",
51
+ :default=>nil,
52
+ :indexed=>false,
53
+ :scale=>nil,
54
+ :primary=>nil,
55
+ :sql_type=>12,
56
+ :nullable=>true,
57
+ :type_name=>"character varying"
58
+ }
59
+ ], cols.collect { |x| x.reject { |key, value| key == :dbi_type } }
60
+ )
61
+
62
+ assert_equal(([DBI::DBD::Pg::Type::Array] * 4), cols.collect { |x| x["dbi_type"].class })
63
+ assert_equal((([DBI::Type::Integer] * 3) + [DBI::Type::Varchar]), cols.collect { |x| x["dbi_type"].base_type })
64
+ end
65
+ end
66
+
67
+ def test_array_parser
68
+ # string representation
69
+ assert_nothing_raised do
70
+ sth = @dbh.prepare('insert into array_test (foo) values (?)')
71
+ sth.execute('{1,2,3}')
72
+ sth.finish
73
+ end
74
+
75
+ assert_nothing_raised do
76
+ sth = @dbh.prepare('insert into array_test (foo) values (?)')
77
+ sth.execute([1,2,3])
78
+ sth.finish
79
+ end
80
+
81
+ assert_nothing_raised do
82
+ sth = @dbh.prepare('insert into array_test (quux) values (?)')
83
+ sth.execute(["Hello\\ World", "Again\\"])
84
+ sth.finish
85
+ end
86
+
87
+ assert_nothing_raised do
88
+ sth = @dbh.prepare('select foo from array_test where foo is not null')
89
+ sth.execute
90
+ assert_equal(
91
+ [
92
+ [[1,2,3]],
93
+ [[1,2,3]],
94
+ ], sth.fetch_all
95
+ )
96
+ sth.finish
97
+
98
+ sth = @dbh.prepare('select quux from array_test where quux is not null')
99
+ sth.execute
100
+
101
+ assert_equal(
102
+ [
103
+ [["Hello\\ World", "Again\\"]]
104
+ ], sth.fetch_all
105
+ )
106
+
107
+ sth.finish
108
+ end
109
+ end
110
+
111
+ def test_array_boundaries
112
+ # bar has a max extents of 3
113
+ sth = @dbh.prepare('insert into array_test (bar) values (?)')
114
+
115
+ assert_nothing_raised do
116
+ sth.execute('{1,2,3}')
117
+ end
118
+
119
+ # XXX postgresql does not enforce extents on single-dimension arrays
120
+ assert_nothing_raised do
121
+ sth.execute('{1,2,3,4}')
122
+ end
123
+
124
+ sth.finish
125
+ sth = @dbh.prepare('insert into array_test(baz) values (?)')
126
+
127
+ assert_nothing_raised do
128
+ sth.execute('{{1,2,3}, {1,2,3}}')
129
+ end
130
+
131
+ assert_nothing_raised do
132
+ # XXX for the record, I have no fucking idea why this works, what
133
+ # it's technically represented as and what backwards array
134
+ # implementation would allow it to work.
135
+ #
136
+ # I'm hoping it'll break on some future version of postgresql so I
137
+ # can fix it.
138
+ sth.execute('{1,2,3}')
139
+ end
140
+
141
+ assert_raises(DBI::ProgrammingError) do
142
+ sth.execute('{{1,2,3,4}, {1,2,3}}')
143
+ end
144
+
145
+ assert_raises(DBI::ProgrammingError) do
146
+ sth.execute('{{1,2,3}, {1,2,3,4}}')
147
+ end
148
+
149
+ sth.finish
150
+ end
151
+
152
+ def test_array_type_parser
153
+ pc = DBI::DBD::Pg::Type::Array
154
+
155
+ assert_nothing_raised do
156
+ po = pc.new(DBI::Type::Integer)
157
+ assert_equal([1,2,3], po.parse("{1,2,3}"))
158
+ assert_equal([[1,2,3],[4,5,6]], po.parse("{{1,2,3},{4,5,6}}"))
159
+ end
160
+
161
+ assert_nothing_raised do
162
+ po = pc.new(DBI::Type::Varchar)
163
+ assert_equal(["one", "two", "three"], po.parse("{\"one\",\"two\",\"three\"}"))
164
+ assert_equal([["one"], ["two\\"]], po.parse("{{\"one\"},{\"two\\\\\"}}"))
165
+ assert_equal([["one", "two\\"], ["three\\", "four"]], po.parse("{{\"one\",\"two\\\\\"},{\"three\\\\\",\"four\"}}"))
166
+ end
167
+ end
168
+
169
+ def test_array_generator
170
+ pg = DBI::DBD::Pg
171
+
172
+ assert_nothing_raised do
173
+ assert_equal("{1,2,3}", pg.generate_array([1,2,3]))
174
+ assert_equal("{{1,2,3},{1,2,3}}", pg.generate_array([[1,2,3],[1,2,3]]))
175
+ assert_equal("{\"one\",\"two\"}", pg.generate_array(["one", "two"]))
176
+ assert_equal("{\"hello\\\\ world\",\"again\"}", pg.generate_array(["hello\\ world", "again"]))
177
+ end
178
+ end
179
+ end