sequel_pg 1.0.0-x86-mswin32-60
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.
- data/CHANGELOG +3 -0
- data/LICENSE +19 -0
- data/README.rdoc +138 -0
- data/Rakefile +21 -0
- data/ext/sequel_pg/extconf.rb +16 -0
- data/ext/sequel_pg/sequel_pg.c +357 -0
- data/lib/1.8/sequel_pg.so +0 -0
- data/lib/1.9/sequel_pg.so +0 -0
- metadata +120 -0
data/CHANGELOG
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010 Jeremy Evans
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
19
|
+
|
data/README.rdoc
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
= sequel_pg
|
2
|
+
|
3
|
+
sequel_pg overwrites the inner loop of the Sequel postgres adapter
|
4
|
+
row fetching code with a C version. The C version is significantly
|
5
|
+
faster (2-6x) than the pure ruby version that Sequel uses by default.
|
6
|
+
|
7
|
+
== Real world difference
|
8
|
+
|
9
|
+
The speed up that sequel_pg gives you depends on what you are
|
10
|
+
selecting, but it should be noticable whenever many rows are selected.
|
11
|
+
Here's an example that shows the difference it makes on a couple of
|
12
|
+
models:
|
13
|
+
|
14
|
+
$ irb -r model -r benchmark
|
15
|
+
irb(main):001:0> Track.count
|
16
|
+
=> 140854
|
17
|
+
irb(main):002:0> Album.count
|
18
|
+
=> 5579
|
19
|
+
irb(main):003:0> puts Benchmark.measure{Track.each{}}
|
20
|
+
10.740000 0.190000 10.930000 ( 11.875343)
|
21
|
+
=> nil
|
22
|
+
irb(main):004:0> puts Benchmark.measure{10.times{Album.each{}}}
|
23
|
+
7.920000 0.070000 7.990000 ( 8.482130)
|
24
|
+
=> nil
|
25
|
+
irb(main):005:0> require '/data/code/sequel_pg/ext/sequel_pg/sequel_pg'
|
26
|
+
=> true
|
27
|
+
irb(main):006:0> puts Benchmark.measure{Track.each{}}
|
28
|
+
2.360000 0.400000 2.760000 ( 3.723098)
|
29
|
+
=> nil
|
30
|
+
irb(main):007:0> puts Benchmark.measure{10.times{Album.each{}}}
|
31
|
+
1.300000 0.190000 1.490000 ( 2.001393)
|
32
|
+
=> nil
|
33
|
+
|
34
|
+
Here's an example that uses a modified version of swift's benchmarks
|
35
|
+
(http://github.com/shanna/swift/tree/master/benchmarks/):
|
36
|
+
|
37
|
+
benchmark sys user total real rss
|
38
|
+
sequel #select 0.090000 2.020000 2.110000 2.246688 46.54m
|
39
|
+
sequel_pg #select 0.000000 0.250000 0.250000 0.361999 7.33m
|
40
|
+
|
41
|
+
== Installing the gem
|
42
|
+
|
43
|
+
gem install sequel_pg
|
44
|
+
|
45
|
+
The standard gem requires compiling from source, so you need a working
|
46
|
+
compiler toolchain. Since few Windows users have a working compiler
|
47
|
+
toolchain, a windows binary gem is available that works on both 1.8
|
48
|
+
and 1.9.
|
49
|
+
|
50
|
+
== Running the specs
|
51
|
+
|
52
|
+
sequel_pg doesn't ship with it's own specs. It's designed to
|
53
|
+
replace a part of Sequel, so it just uses Sequel's specs.
|
54
|
+
Specifically, the spec_postgres spec from Sequel.
|
55
|
+
|
56
|
+
== Reporting issues/bugs
|
57
|
+
|
58
|
+
sequel_pg uses GitHub Issues for tracking issues/bugs:
|
59
|
+
|
60
|
+
http://github.com/jeremyevans/sequel_pg/issues
|
61
|
+
|
62
|
+
== Contributing
|
63
|
+
|
64
|
+
The source code is on GitHub:
|
65
|
+
|
66
|
+
http://github.com/jeremyevans/sequel_pg
|
67
|
+
|
68
|
+
To get a copy:
|
69
|
+
|
70
|
+
git clone git://github.com/jeremyevans/sequel_pg.git
|
71
|
+
|
72
|
+
There are only a few requirements, which you should probably
|
73
|
+
have before considering use of the library:
|
74
|
+
|
75
|
+
* Rake
|
76
|
+
* Sequel
|
77
|
+
* pg
|
78
|
+
* libpq headers and library
|
79
|
+
|
80
|
+
== Building
|
81
|
+
|
82
|
+
To build the library from a git checkout, after installing the
|
83
|
+
requirements:
|
84
|
+
|
85
|
+
rake build
|
86
|
+
|
87
|
+
== Platforms Supported
|
88
|
+
|
89
|
+
sequel_pg has been tested on the following:
|
90
|
+
|
91
|
+
=== Operating Systems/Platforms
|
92
|
+
|
93
|
+
* Linux (i386)
|
94
|
+
* OpenBSD (amd64, i386)
|
95
|
+
* Windows XP (i386)
|
96
|
+
|
97
|
+
=== Compiler Versions
|
98
|
+
|
99
|
+
* gcc (3.3.5, 4.2.1, 4.4.3)
|
100
|
+
|
101
|
+
=== Ruby Versions
|
102
|
+
|
103
|
+
* jruby cext branch (compiles but untested and unusable, as pg itself
|
104
|
+
doesn't compile yet)
|
105
|
+
* rbx head
|
106
|
+
* ruby 1.8.6
|
107
|
+
* ruby 1.8.7
|
108
|
+
* ruby 1.9.1
|
109
|
+
* ruby 1.9.2
|
110
|
+
* ruby head
|
111
|
+
|
112
|
+
If your platform, compiler version, or ruby version is not listed
|
113
|
+
above, please test and send me a report including:
|
114
|
+
|
115
|
+
* Your operating system and platform (e.g. i386, x86_64/amd64)
|
116
|
+
* Your compiler
|
117
|
+
* Your ruby version
|
118
|
+
|
119
|
+
== Known Issues
|
120
|
+
|
121
|
+
* You must be using the ISO PostgreSQL date format (which is the
|
122
|
+
default). Using the SQL, POSTGRESQL, or GERMAN date formats will
|
123
|
+
result in incorrect date/timestamp handling. In addition to
|
124
|
+
PostgreSQL defaulting to ISO, Sequel also manually sets the
|
125
|
+
date format to ISO by default, so unless you are overriding that
|
126
|
+
setting (via Sequel::Postgres.use_iso_date_format = false), you
|
127
|
+
should be OK.
|
128
|
+
* Adding your own type conversion procs to Sequel::Postgres::PG_TYPES
|
129
|
+
does not have an effect with this plugin, since the type conversion
|
130
|
+
is done in C.
|
131
|
+
* The named_timezones plugin does not integrate with sequel_pg, since
|
132
|
+
sequel_pg does it's own timestamp conversions. The :local and :utc
|
133
|
+
settings for database_timestamp and application_timestamp do work,
|
134
|
+
as does setting the datetime_class to DateTime.
|
135
|
+
|
136
|
+
== Author
|
137
|
+
|
138
|
+
Jeremy Evans <code@jeremyevans.net>
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "rake"
|
2
|
+
require "rake/clean"
|
3
|
+
|
4
|
+
CLEAN.include %w'**.rbc rdoc'
|
5
|
+
|
6
|
+
desc "Do a full cleaning"
|
7
|
+
task :distclean do
|
8
|
+
CLEAN.include %w'tmp pkg sequel_pg*.gem lib'
|
9
|
+
Rake::Task[:clean].invoke
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Build the gem"
|
13
|
+
task :gem do
|
14
|
+
sh %{gem build sequel_pg.gemspec}
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'rake/extensiontask'
|
19
|
+
Rake::ExtensionTask.new('sequel_pg')
|
20
|
+
rescue LoadError
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
$CFLAGS << " -Wall " unless RUBY_PLATFORM =~ /solaris/
|
3
|
+
dir_config('pg', ENV["POSTGRES_INCLUDE"] || (IO.popen("pg_config --includedir").readline.chomp rescue nil),
|
4
|
+
ENV["POSTGRES_LIB"] || (IO.popen("pg_config --libdir").readline.chomp rescue nil))
|
5
|
+
|
6
|
+
if enable_config("static-build")
|
7
|
+
# Link against all required libraries for static build, if they are available
|
8
|
+
have_library('gdi32', 'CreateDC') && append_library($libs, 'gdi32')
|
9
|
+
have_library('secur32') && append_library($libs, 'secur32')
|
10
|
+
end
|
11
|
+
|
12
|
+
if (have_library('pq') || have_library('libpq') || have_library('ms/libpq')) && have_header('libpq-fe.h')
|
13
|
+
create_makefile("sequel_pg")
|
14
|
+
else
|
15
|
+
puts 'Could not find PostgreSQL build environment (libraries & headers): Makefile not created'
|
16
|
+
end
|
@@ -0,0 +1,357 @@
|
|
1
|
+
#include <string.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <math.h>
|
4
|
+
#include <libpq-fe.h>
|
5
|
+
#include <ruby.h>
|
6
|
+
|
7
|
+
#if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
|
8
|
+
#define SPG_ENCODING 1
|
9
|
+
#include <ruby/encoding.h>
|
10
|
+
#endif
|
11
|
+
|
12
|
+
#define SPG_MAX_FIELDS 256
|
13
|
+
#define SPG_MILLISECONDS_PER_DAY 86400000000.0
|
14
|
+
#define SPG_MINUTES_PER_DAY 1440.0
|
15
|
+
#define SPG_SECONDS_PER_DAY 86400.0
|
16
|
+
|
17
|
+
#define SPG_DT_ADD_USEC if (usec != 0) { dt = rb_funcall(dt, spg_id_op_plus, 1, rb_float_new(usec/SPG_MILLISECONDS_PER_DAY)); }
|
18
|
+
|
19
|
+
#define SPG_NO_TZ 0
|
20
|
+
#define SPG_DB_LOCAL 1
|
21
|
+
#define SPG_DB_UTC 2
|
22
|
+
#define SPG_APP_LOCAL 4
|
23
|
+
#define SPG_APP_UTC 8
|
24
|
+
|
25
|
+
static VALUE spg_Sequel;
|
26
|
+
static VALUE spg_Blob;
|
27
|
+
static VALUE spg_BigDecimal;
|
28
|
+
static VALUE spg_Date;
|
29
|
+
|
30
|
+
static VALUE spg_sym_utc;
|
31
|
+
static VALUE spg_sym_local;
|
32
|
+
|
33
|
+
static ID spg_id_new;
|
34
|
+
static ID spg_id_local;
|
35
|
+
static ID spg_id_year;
|
36
|
+
static ID spg_id_month;
|
37
|
+
static ID spg_id_day;
|
38
|
+
static ID spg_id_output_identifier;
|
39
|
+
static ID spg_id_datetime_class;
|
40
|
+
static ID spg_id_application_timezone;
|
41
|
+
static ID spg_id_database_timezone;
|
42
|
+
static ID spg_id_op_plus;
|
43
|
+
static ID spg_id_utc;
|
44
|
+
static ID spg_id_utc_offset;
|
45
|
+
static ID spg_id_localtime;
|
46
|
+
static ID spg_id_new_offset;
|
47
|
+
|
48
|
+
static ID spg_id_columns;
|
49
|
+
static ID spg_id_encoding;
|
50
|
+
|
51
|
+
#if SPG_ENCODING
|
52
|
+
static int enc_get_index(VALUE val)
|
53
|
+
{
|
54
|
+
int i = ENCODING_GET_INLINED(val);
|
55
|
+
if (i == ENCODING_INLINE_MAX) {
|
56
|
+
i = NUM2INT(rb_ivar_get(val, spg_id_encoding));
|
57
|
+
}
|
58
|
+
return i;
|
59
|
+
}
|
60
|
+
#endif
|
61
|
+
|
62
|
+
static VALUE spg_time(const char *s) {
|
63
|
+
VALUE now;
|
64
|
+
int hour, minute, second, tokens;
|
65
|
+
char subsec[7];
|
66
|
+
int usec = 0;
|
67
|
+
|
68
|
+
tokens = sscanf(s, "%2d:%2d:%2d.%s", &hour, &minute, &second, subsec);
|
69
|
+
if(tokens == 4) {
|
70
|
+
usec = atoi(subsec);
|
71
|
+
usec *= (int) pow(10, (6 - strlen(subsec)));
|
72
|
+
} else if(tokens < 3) {
|
73
|
+
rb_raise(rb_eArgError, "unexpected time format");
|
74
|
+
}
|
75
|
+
|
76
|
+
now = rb_funcall(rb_cTime, spg_id_new, 0);
|
77
|
+
return rb_funcall(rb_cTime, spg_id_local, 6, rb_funcall(now, spg_id_year, 0), rb_funcall(now, spg_id_month, 0), rb_funcall(now, spg_id_day, 0), INT2NUM(hour), INT2NUM(minute), INT2NUM(second), INT2NUM(usec));
|
78
|
+
}
|
79
|
+
|
80
|
+
static VALUE spg_date(const char *s) {
|
81
|
+
int year, month, day;
|
82
|
+
|
83
|
+
if(3 != sscanf(s, "%d-%2d-%2d", &year, &month, &day)) {
|
84
|
+
rb_raise(rb_eArgError, "unexpected date format");
|
85
|
+
}
|
86
|
+
|
87
|
+
return rb_funcall(spg_Date, spg_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
|
88
|
+
}
|
89
|
+
|
90
|
+
static VALUE spg_timestamp(const char *s) {
|
91
|
+
VALUE dtc, dt, rtz;
|
92
|
+
int tz = SPG_NO_TZ;
|
93
|
+
int year, month, day, hour, min, sec, usec, tokens, pos, utc_offset;
|
94
|
+
int check_offset = 0;
|
95
|
+
int offset_hour = 0;
|
96
|
+
int offset_minute = 0;
|
97
|
+
int offset_seconds = 0;
|
98
|
+
double offset_fraction = 0.0;
|
99
|
+
char subsec[7];
|
100
|
+
|
101
|
+
if (0 != strchr(s, '.')) {
|
102
|
+
tokens = sscanf(s, "%d-%2d-%2d %2d:%2d:%2d.%s%n", &year, &month, &day, &hour, &min, &sec, subsec, &pos);
|
103
|
+
if (tokens == 8) {
|
104
|
+
check_offset = 1;
|
105
|
+
}
|
106
|
+
if(tokens != 7) {
|
107
|
+
rb_raise(rb_eArgError, "unexpected datetime format");
|
108
|
+
}
|
109
|
+
usec = atoi(subsec);
|
110
|
+
usec *= (int) pow(10, (6 - strlen(subsec)));
|
111
|
+
} else {
|
112
|
+
tokens = sscanf(s, "%d-%2d-%2d %2d:%2d:%2d%n", &year, &month, &day, &hour, &min, &sec, &pos);
|
113
|
+
if (tokens == 3) {
|
114
|
+
hour = 0;
|
115
|
+
min = 0;
|
116
|
+
sec = 0;
|
117
|
+
} else if (tokens == 7) {
|
118
|
+
check_offset = 1;
|
119
|
+
} else if (tokens != 6) {
|
120
|
+
rb_raise(rb_eArgError, "unexpected datetime format");
|
121
|
+
}
|
122
|
+
usec = 0;
|
123
|
+
}
|
124
|
+
|
125
|
+
if (check_offset) {
|
126
|
+
if(sscanf(s + pos, "%3d:%2d", &offset_hour, &offset_minute) == 0) {
|
127
|
+
/* No offset found */
|
128
|
+
check_offset = 0;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
/* Get values of datetime_class, database_timezone, and application_timezone */
|
133
|
+
dtc = rb_funcall(spg_Sequel, spg_id_datetime_class, 0);
|
134
|
+
rtz = rb_funcall(spg_Sequel, spg_id_database_timezone, 0);
|
135
|
+
if (rtz == spg_sym_local) {
|
136
|
+
tz += SPG_DB_LOCAL;
|
137
|
+
} else if (rtz == spg_sym_utc) {
|
138
|
+
tz += SPG_DB_UTC;
|
139
|
+
}
|
140
|
+
rtz = rb_funcall(spg_Sequel, spg_id_application_timezone, 0);
|
141
|
+
if (rtz == spg_sym_local) {
|
142
|
+
tz += SPG_APP_LOCAL;
|
143
|
+
} else if (rtz == spg_sym_utc) {
|
144
|
+
tz += SPG_APP_UTC;
|
145
|
+
}
|
146
|
+
|
147
|
+
if (dtc == rb_cTime) {
|
148
|
+
if (check_offset) {
|
149
|
+
/* Offset given, convert to local time if not already in local time.
|
150
|
+
* While PostgreSQL generally returns timestamps in local time, it's unwise to rely on this.
|
151
|
+
*/
|
152
|
+
dt = rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
153
|
+
utc_offset = NUM2INT(rb_funcall(dt, spg_id_utc_offset, 0));
|
154
|
+
offset_seconds = offset_hour * 3600 + offset_minute * 60;
|
155
|
+
if (utc_offset != offset_seconds) {
|
156
|
+
dt = rb_funcall(dt, spg_id_op_plus, 1, INT2NUM(utc_offset - offset_seconds));
|
157
|
+
}
|
158
|
+
|
159
|
+
if (tz & SPG_APP_UTC) {
|
160
|
+
dt = rb_funcall(dt, spg_id_utc, 0);
|
161
|
+
}
|
162
|
+
return dt;
|
163
|
+
} else if (tz == SPG_NO_TZ) {
|
164
|
+
return rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
165
|
+
}
|
166
|
+
|
167
|
+
/* No offset given, and some timezone combination given */
|
168
|
+
if (tz & SPG_DB_UTC) {
|
169
|
+
dt = rb_funcall(rb_cTime, spg_id_utc, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
170
|
+
if (tz & SPG_APP_LOCAL) {
|
171
|
+
return rb_funcall(dt, spg_id_localtime, 0);
|
172
|
+
} else {
|
173
|
+
return dt;
|
174
|
+
}
|
175
|
+
} else {
|
176
|
+
dt = rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
177
|
+
if (tz & SPG_APP_UTC) {
|
178
|
+
return rb_funcall(dt, spg_id_utc, 0);
|
179
|
+
} else {
|
180
|
+
return dt;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
} else {
|
184
|
+
/* datetime.class == DateTime */
|
185
|
+
if (check_offset) {
|
186
|
+
/* Offset given, handle correct local time.
|
187
|
+
* While PostgreSQL generally returns timestamps in local time, it's unwise to rely on this.
|
188
|
+
*/
|
189
|
+
offset_fraction = offset_hour/24.0 + offset_minute/SPG_MINUTES_PER_DAY;
|
190
|
+
dt = rb_funcall(dtc, spg_id_new, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), rb_float_new(offset_fraction));
|
191
|
+
SPG_DT_ADD_USEC
|
192
|
+
|
193
|
+
if (tz & SPG_APP_LOCAL) {
|
194
|
+
utc_offset = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_new, 0), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
|
195
|
+
dt = rb_funcall(dt, spg_id_new_offset, 1, rb_float_new(utc_offset));
|
196
|
+
} else if (tz & SPG_APP_UTC) {
|
197
|
+
dt = rb_funcall(dt, spg_id_new_offset, 1, INT2NUM(0));
|
198
|
+
}
|
199
|
+
return dt;
|
200
|
+
} else if (tz == SPG_NO_TZ) {
|
201
|
+
dt = rb_funcall(dtc, spg_id_new, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
202
|
+
SPG_DT_ADD_USEC
|
203
|
+
return dt;
|
204
|
+
}
|
205
|
+
|
206
|
+
/* No offset given, and some timezone combination given */
|
207
|
+
if (tz & SPG_DB_LOCAL) {
|
208
|
+
offset_fraction = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
|
209
|
+
dt = rb_funcall(dtc, spg_id_new, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), rb_float_new(offset_fraction));
|
210
|
+
SPG_DT_ADD_USEC
|
211
|
+
if (tz & SPG_APP_UTC) {
|
212
|
+
return rb_funcall(dt, spg_id_new_offset, 1, INT2NUM(0));
|
213
|
+
} else {
|
214
|
+
return dt;
|
215
|
+
}
|
216
|
+
} else {
|
217
|
+
dt = rb_funcall(dtc, spg_id_new, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
218
|
+
SPG_DT_ADD_USEC
|
219
|
+
if (tz & SPG_APP_LOCAL) {
|
220
|
+
offset_fraction = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
|
221
|
+
return rb_funcall(dt, spg_id_new_offset, 1, rb_float_new(offset_fraction));
|
222
|
+
} else {
|
223
|
+
return dt;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
static VALUE spg_fetch_rows_set_cols(VALUE self, VALUE ignore) {
|
230
|
+
return self;
|
231
|
+
}
|
232
|
+
|
233
|
+
static VALUE spg_yield_hash_rows(VALUE self, VALUE rres, VALUE ignore) {
|
234
|
+
PGresult *res;
|
235
|
+
VALUE colsyms[SPG_MAX_FIELDS];
|
236
|
+
long ntuples;
|
237
|
+
long nfields;
|
238
|
+
long i;
|
239
|
+
long j;
|
240
|
+
VALUE h, rv;
|
241
|
+
size_t l;
|
242
|
+
char * v;
|
243
|
+
|
244
|
+
#ifdef SPG_ENCODING
|
245
|
+
int enc_index;
|
246
|
+
enc_index = enc_get_index(rres);
|
247
|
+
#endif
|
248
|
+
|
249
|
+
Data_Get_Struct(rres, PGresult, res);
|
250
|
+
ntuples = PQntuples(res);
|
251
|
+
nfields = PQnfields(res);
|
252
|
+
if (nfields > SPG_MAX_FIELDS) {
|
253
|
+
rb_raise(rb_eRangeError, "more than %d columns in query", SPG_MAX_FIELDS);
|
254
|
+
}
|
255
|
+
|
256
|
+
for(j=0; j<nfields; j++) {
|
257
|
+
colsyms[j] = rb_funcall(self, spg_id_output_identifier, 1, rb_str_new2(PQfname(res, j)));
|
258
|
+
}
|
259
|
+
rb_ivar_set(self, spg_id_columns, rb_ary_new4(nfields, colsyms));
|
260
|
+
|
261
|
+
for(i=0; i<ntuples; i++) {
|
262
|
+
h = rb_hash_new();
|
263
|
+
for(j=0; j<nfields; j++) {
|
264
|
+
if(PQgetisnull(res, i, j)) {
|
265
|
+
rv = Qnil;
|
266
|
+
} else {
|
267
|
+
v = PQgetvalue(res, i, j);
|
268
|
+
|
269
|
+
switch(PQftype(res, j)) {
|
270
|
+
case 16: /* boolean */
|
271
|
+
rv = *v == 't' ? Qtrue : Qfalse;
|
272
|
+
break;
|
273
|
+
case 17: /* bytea */
|
274
|
+
v = (char *)PQunescapeBytea((unsigned char*)v, &l);
|
275
|
+
rv = rb_funcall(spg_Blob, spg_id_new, 1, rb_str_new(v, l));
|
276
|
+
PQfreemem(v);
|
277
|
+
break;
|
278
|
+
case 20: /* integer */
|
279
|
+
case 21:
|
280
|
+
case 22:
|
281
|
+
case 23:
|
282
|
+
case 26:
|
283
|
+
rv = rb_cstr2inum(v, 10);
|
284
|
+
break;
|
285
|
+
case 700: /* float */
|
286
|
+
case 701:
|
287
|
+
rv = rb_float_new(rb_cstr_to_dbl(v, Qfalse));
|
288
|
+
break;
|
289
|
+
case 790: /* numeric */
|
290
|
+
case 1700:
|
291
|
+
rv = rb_funcall(spg_BigDecimal, spg_id_new, 1, rb_str_new(v, PQgetlength(res, i, j)));
|
292
|
+
break;
|
293
|
+
case 1082: /* date */
|
294
|
+
rv = spg_date(v);
|
295
|
+
break;
|
296
|
+
case 1083: /* time */
|
297
|
+
case 1266:
|
298
|
+
rv = spg_time(v);
|
299
|
+
break;
|
300
|
+
case 1114: /* timestamp */
|
301
|
+
case 1184:
|
302
|
+
rv = spg_timestamp(v);
|
303
|
+
break;
|
304
|
+
default:
|
305
|
+
rv = rb_tainted_str_new(v, PQgetlength(res, i, j));
|
306
|
+
#ifdef SPG_ENCODING
|
307
|
+
rb_enc_associate_index(rv, enc_index);
|
308
|
+
#endif
|
309
|
+
}
|
310
|
+
}
|
311
|
+
rb_hash_aset(h, colsyms[j], rv);
|
312
|
+
}
|
313
|
+
rb_yield(h);
|
314
|
+
}
|
315
|
+
|
316
|
+
return self;
|
317
|
+
}
|
318
|
+
|
319
|
+
void Init_sequel_pg(void) {
|
320
|
+
VALUE c;
|
321
|
+
ID cg;
|
322
|
+
cg = rb_intern("const_get");
|
323
|
+
spg_id_new = rb_intern("new");
|
324
|
+
spg_id_local = rb_intern("local");
|
325
|
+
spg_id_year = rb_intern("year");
|
326
|
+
spg_id_month = rb_intern("month");
|
327
|
+
spg_id_day = rb_intern("day");
|
328
|
+
spg_id_output_identifier = rb_intern("output_identifier");
|
329
|
+
spg_id_datetime_class = rb_intern("datetime_class");
|
330
|
+
spg_id_application_timezone = rb_intern("application_timezone");
|
331
|
+
spg_id_database_timezone = rb_intern("database_timezone");
|
332
|
+
spg_id_op_plus = rb_intern("+");
|
333
|
+
spg_id_utc = rb_intern("utc");
|
334
|
+
spg_id_utc_offset = rb_intern("utc_offset");
|
335
|
+
spg_id_localtime = rb_intern("localtime");
|
336
|
+
spg_id_new_offset = rb_intern("new_offset");
|
337
|
+
|
338
|
+
spg_id_columns = rb_intern("@columns");
|
339
|
+
spg_id_encoding = rb_intern("@encoding");
|
340
|
+
|
341
|
+
spg_sym_utc = ID2SYM(rb_intern("utc"));
|
342
|
+
spg_sym_local = ID2SYM(rb_intern("local"));
|
343
|
+
|
344
|
+
spg_Sequel = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Sequel"));
|
345
|
+
spg_Blob = rb_funcall(rb_funcall(spg_Sequel, cg, 1, rb_str_new2("SQL")), cg, 1, rb_str_new2("Blob"));
|
346
|
+
spg_BigDecimal = rb_funcall(rb_cObject, cg, 1, rb_str_new2("BigDecimal"));
|
347
|
+
spg_Date = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Date"));
|
348
|
+
|
349
|
+
rb_global_variable(&spg_Sequel);
|
350
|
+
rb_global_variable(&spg_Blob);
|
351
|
+
rb_global_variable(&spg_BigDecimal);
|
352
|
+
rb_global_variable(&spg_Date);
|
353
|
+
|
354
|
+
c = rb_funcall(rb_funcall(spg_Sequel, cg, 1, rb_str_new2("Postgres")), cg, 1, rb_str_new2("Dataset"));
|
355
|
+
rb_define_private_method(c, "yield_hash_rows", spg_yield_hash_rows, 2);
|
356
|
+
rb_define_private_method(c, "fetch_rows_set_cols", spg_fetch_rows_set_cols, 1);
|
357
|
+
}
|
Binary file
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequel_pg
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: x86-mswin32-60
|
12
|
+
authors:
|
13
|
+
- Jeremy Evans
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-31 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: pg
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 63
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 8
|
33
|
+
- 0
|
34
|
+
version: 0.8.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: sequel
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 31
|
46
|
+
segments:
|
47
|
+
- 3
|
48
|
+
- 6
|
49
|
+
- 0
|
50
|
+
version: 3.6.0
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: |
|
54
|
+
sequel_pg overwrites the inner loop of the Sequel postgres
|
55
|
+
adapter row fetching code with a C version. The C version
|
56
|
+
is significantly faster (2-6x) than the pure ruby version
|
57
|
+
that Sequel uses by default.
|
58
|
+
|
59
|
+
email: code@jeremyevans.net
|
60
|
+
executables: []
|
61
|
+
|
62
|
+
extensions: []
|
63
|
+
|
64
|
+
extra_rdoc_files:
|
65
|
+
- README.rdoc
|
66
|
+
- CHANGELOG
|
67
|
+
- LICENSE
|
68
|
+
files:
|
69
|
+
- LICENSE
|
70
|
+
- CHANGELOG
|
71
|
+
- README.rdoc
|
72
|
+
- Rakefile
|
73
|
+
- ext/sequel_pg/extconf.rb
|
74
|
+
- ext/sequel_pg/sequel_pg.c
|
75
|
+
- lib/1.8/sequel_pg.so
|
76
|
+
- lib/1.9/sequel_pg.so
|
77
|
+
has_rdoc: true
|
78
|
+
homepage: http://github.com/jeremyevans/sequel_pg
|
79
|
+
licenses: []
|
80
|
+
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options:
|
83
|
+
- --quiet
|
84
|
+
- --line-numbers
|
85
|
+
- --inline-source
|
86
|
+
- --title
|
87
|
+
- "sequel_pg: Faster SELECTs when using Sequel with pg"
|
88
|
+
- --main
|
89
|
+
- README.rdoc
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
hash: 59
|
98
|
+
segments:
|
99
|
+
- 1
|
100
|
+
- 8
|
101
|
+
- 6
|
102
|
+
version: 1.8.6
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
version: "0"
|
112
|
+
requirements: []
|
113
|
+
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 1.3.7
|
116
|
+
signing_key:
|
117
|
+
specification_version: 3
|
118
|
+
summary: Faster SELECTs when using Sequel with pg
|
119
|
+
test_files: []
|
120
|
+
|