ruby_snowflake_client 1.0.2 → 1.1.0
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/Gemfile.lock +1 -1
- data/ext/c-decl.go +2 -2
- data/ext/result.go +50 -59
- data/ext/ruby_snowflake.go +30 -42
- data/ext/wrapper.go +5 -4
- data/lib/ruby_snowflake_client/version.rb +1 -1
- data/lib/ruby_snowflake_client.rb +15 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75899b8f6ba98da01620d76f6d7077ba73ae8dd7fb1177815300b969d0dbf7b5
|
4
|
+
data.tar.gz: 2fdbd266149c69bf17d59c83ab09418ca8f46d23707c5c3d98cc8e6800bf84e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 180122aebc707aeda9e7cff2fad9ab6361b21d027b4dc23961bb64319ae192338091fff3b5600cbc15a86522c39bff2b4402723c7c0dfbd80570bdea3e3f96cb
|
7
|
+
data.tar.gz: 65ab2555c42a044224ee1f5e010f43f7ddc9491205d271bd4459459ee5ffb3f65112bd310742c1bcab797c66e8a590e96f732032142ba3866e2e91afb5feb40b
|
data/Gemfile.lock
CHANGED
data/ext/c-decl.go
CHANGED
@@ -29,9 +29,9 @@ func goobj_log(obj unsafe.Pointer) {
|
|
29
29
|
}
|
30
30
|
|
31
31
|
//export goobj_retain
|
32
|
-
func goobj_retain(obj unsafe.Pointer) {
|
32
|
+
func goobj_retain(obj unsafe.Pointer, x *C.char) {
|
33
33
|
if LOG_LEVEL > 0 {
|
34
|
-
fmt.Printf("retain obj %v - currently keeping %d\n", obj, len(objects))
|
34
|
+
fmt.Printf("retain obj [%v] %v - currently keeping %d\n", C.GoString(x), obj, len(objects))
|
35
35
|
}
|
36
36
|
objects[obj] = true
|
37
37
|
marked[obj] = 0
|
data/ext/result.go
CHANGED
@@ -11,11 +11,8 @@ VALUE funcall0param(VALUE obj, ID id);
|
|
11
11
|
import "C"
|
12
12
|
|
13
13
|
import (
|
14
|
-
"errors"
|
15
14
|
"fmt"
|
16
|
-
"io"
|
17
15
|
"math/big"
|
18
|
-
"strings"
|
19
16
|
"time"
|
20
17
|
|
21
18
|
gopointer "github.com/mattn/go-pointer"
|
@@ -28,18 +25,44 @@ func wrapRbRaise(err error) {
|
|
28
25
|
}
|
29
26
|
|
30
27
|
func getResultStruct(self C.VALUE) *SnowflakeResult {
|
31
|
-
|
28
|
+
return resultMap[self]
|
29
|
+
}
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
//export GetRowsNoEnum
|
32
|
+
func GetRowsNoEnum(self C.VALUE) C.VALUE {
|
33
|
+
res := getResultStruct(self)
|
34
|
+
rows := res.rows
|
35
|
+
|
36
|
+
i := 0
|
37
|
+
t1 := time.Now()
|
38
|
+
var arr []C.VALUE
|
39
|
+
|
40
|
+
for rows.Next() {
|
41
|
+
if i%5000 == 0 {
|
42
|
+
if LOG_LEVEL > 0 {
|
43
|
+
fmt.Println("scanning row: ", i)
|
44
|
+
}
|
45
|
+
}
|
46
|
+
x := res.ScanNextRow(false)
|
47
|
+
objects[x] = true
|
48
|
+
gopointer.Save(x)
|
49
|
+
if LOG_LEVEL > 1 {
|
50
|
+
// This is VERY noisy
|
51
|
+
fmt.Printf("alloced %v\n", &x)
|
52
|
+
}
|
53
|
+
arr = append(arr, x)
|
54
|
+
i = i + 1
|
55
|
+
}
|
56
|
+
if LOG_LEVEL > 0 {
|
57
|
+
fmt.Printf("done with rows.next: %s\n", time.Now().Sub(t1))
|
40
58
|
}
|
41
59
|
|
42
|
-
|
60
|
+
rbArr := C.rb_ary_new2(C.long(len(arr)))
|
61
|
+
for idx, elem := range arr {
|
62
|
+
C.rb_ary_store(rbArr, C.long(idx), elem)
|
63
|
+
}
|
64
|
+
|
65
|
+
return rbArr
|
43
66
|
}
|
44
67
|
|
45
68
|
//export GetRows
|
@@ -69,11 +92,6 @@ func GetRows(self C.VALUE) C.VALUE {
|
|
69
92
|
fmt.Printf("done with rows.next: %s\n", time.Now().Sub(t1))
|
70
93
|
}
|
71
94
|
|
72
|
-
//empty for GC
|
73
|
-
res.rows = nil
|
74
|
-
res.keptHash = C.Qnil
|
75
|
-
res.cols = []C.VALUE{}
|
76
|
-
|
77
95
|
return self
|
78
96
|
}
|
79
97
|
|
@@ -89,10 +107,6 @@ func ObjNextRow(self C.VALUE) C.VALUE {
|
|
89
107
|
if rows.Next() {
|
90
108
|
r := res.ScanNextRow(false)
|
91
109
|
return r
|
92
|
-
} else if rows.Err() == io.EOF {
|
93
|
-
res.rows = nil // free up for gc
|
94
|
-
res.keptHash = C.Qnil // free up for gc
|
95
|
-
res.cols = []C.VALUE{}
|
96
110
|
}
|
97
111
|
return C.Qnil
|
98
112
|
}
|
@@ -104,8 +118,8 @@ func (res SnowflakeResult) ScanNextRow(debug bool) C.VALUE {
|
|
104
118
|
fmt.Printf("column types: %+v; %+v\n", cts[0], cts[0].ScanType())
|
105
119
|
}
|
106
120
|
|
107
|
-
rawResult := make([]any, len(res.
|
108
|
-
rawData := make([]any, len(res.
|
121
|
+
rawResult := make([]any, len(res.columns))
|
122
|
+
rawData := make([]any, len(res.columns))
|
109
123
|
for i := range rawResult {
|
110
124
|
rawData[i] = &rawResult[i]
|
111
125
|
}
|
@@ -117,10 +131,15 @@ func (res SnowflakeResult) ScanNextRow(debug bool) C.VALUE {
|
|
117
131
|
}
|
118
132
|
|
119
133
|
// trick from postgres; keep hash: pg_result.c:1088
|
120
|
-
hash := C.rb_hash_dup(res.keptHash)
|
134
|
+
//hash := C.rb_hash_dup(res.keptHash)
|
135
|
+
hash := C.rb_hash_new()
|
136
|
+
if LOG_LEVEL > 1 {
|
137
|
+
// This is very noisy
|
138
|
+
fmt.Println("alloc'ed new hash", &hash)
|
139
|
+
}
|
140
|
+
|
121
141
|
for idx, raw := range rawResult {
|
122
142
|
raw := raw
|
123
|
-
col_name := res.cols[idx]
|
124
143
|
|
125
144
|
var rbVal C.VALUE
|
126
145
|
|
@@ -151,40 +170,12 @@ func (res SnowflakeResult) ScanNextRow(debug bool) C.VALUE {
|
|
151
170
|
wrapRbRaise(err)
|
152
171
|
}
|
153
172
|
}
|
154
|
-
C.
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
var hash C.VALUE
|
161
|
-
hash = C.rb_hash_new()
|
162
|
-
|
163
|
-
if LOG_LEVEL > 0 {
|
164
|
-
fmt.Println("starting make hash")
|
165
|
-
}
|
166
|
-
for _, col := range cols {
|
167
|
-
C.rb_hash_aset(hash, col, C.Qnil)
|
168
|
-
}
|
169
|
-
if LOG_LEVEL > 0 {
|
170
|
-
fmt.Println("end make hash", hash)
|
173
|
+
colstr := C.rb_str_new2(C.CString(res.columns[idx]))
|
174
|
+
if LOG_LEVEL > 1 {
|
175
|
+
// This is very noisy
|
176
|
+
fmt.Printf("alloc string: %+v; rubyVal: %+v\n", &colstr, &rbVal)
|
177
|
+
}
|
178
|
+
C.rb_hash_aset(hash, colstr, rbVal)
|
171
179
|
}
|
172
180
|
return hash
|
173
181
|
}
|
174
|
-
|
175
|
-
func (res *SnowflakeResult) Initialize() {
|
176
|
-
columns, _ := res.rows.Columns()
|
177
|
-
rbArr := C.rb_ary_new2(C.long(len(columns)))
|
178
|
-
|
179
|
-
cols := make([]C.VALUE, len(columns))
|
180
|
-
for idx, colName := range columns {
|
181
|
-
str := strings.ToLower(colName)
|
182
|
-
sym := C.rb_str_new2(C.CString(str))
|
183
|
-
sym = C.rb_str_freeze(sym)
|
184
|
-
cols[idx] = sym
|
185
|
-
C.rb_ary_store(rbArr, C.long(idx), sym)
|
186
|
-
}
|
187
|
-
|
188
|
-
res.cols = cols
|
189
|
-
res.keptHash = SafeMakeHash(len(columns), cols)
|
190
|
-
}
|
data/ext/ruby_snowflake.go
CHANGED
@@ -8,8 +8,9 @@ VALUE ObjFetch(VALUE,VALUE);
|
|
8
8
|
VALUE ObjNextRow(VALUE);
|
9
9
|
VALUE Inspect(VALUE);
|
10
10
|
VALUE GetRows(VALUE);
|
11
|
+
VALUE GetRowsNoEnum(VALUE);
|
11
12
|
|
12
|
-
VALUE NewGoStruct(VALUE klass, void *p);
|
13
|
+
VALUE NewGoStruct(VALUE klass, char* reason, void *p);
|
13
14
|
VALUE GoRetEnum(VALUE,int,VALUE);
|
14
15
|
void* GetGoStruct(VALUE obj);
|
15
16
|
void RbGcGuard(VALUE ptr);
|
@@ -21,18 +22,18 @@ import "C"
|
|
21
22
|
import (
|
22
23
|
"context"
|
23
24
|
"database/sql"
|
24
|
-
"errors"
|
25
25
|
"fmt"
|
26
|
+
"strings"
|
26
27
|
"time"
|
27
28
|
|
28
|
-
gopointer "github.com/mattn/go-pointer"
|
29
29
|
sf "github.com/snowflakedb/gosnowflake"
|
30
30
|
)
|
31
31
|
|
32
32
|
type SnowflakeResult struct {
|
33
|
-
rows
|
34
|
-
keptHash C.VALUE
|
35
|
-
|
33
|
+
rows *sql.Rows
|
34
|
+
//keptHash C.VALUE
|
35
|
+
columns []string
|
36
|
+
//cols []C.VALUE
|
36
37
|
}
|
37
38
|
type SnowflakeClient struct {
|
38
39
|
db *sql.DB
|
@@ -42,12 +43,13 @@ var rbSnowflakeClientClass C.VALUE
|
|
42
43
|
var rbSnowflakeResultClass C.VALUE
|
43
44
|
var rbSnowflakeModule C.VALUE
|
44
45
|
|
45
|
-
var DB_IDENTIFIER = C.rb_intern(C.CString("db"))
|
46
46
|
var RESULT_IDENTIFIER = C.rb_intern(C.CString("rows"))
|
47
47
|
var RESULT_DURATION = C.rb_intern(C.CString("@query_duration"))
|
48
48
|
var ERROR_IDENT = C.rb_intern(C.CString("@error"))
|
49
49
|
|
50
50
|
var objects = make(map[interface{}]bool)
|
51
|
+
var resultMap = make(map[C.VALUE]*SnowflakeResult)
|
52
|
+
var clientRef = make(map[C.VALUE]*SnowflakeClient)
|
51
53
|
|
52
54
|
var LOG_LEVEL = 0
|
53
55
|
var empty C.VALUE = C.Qnil
|
@@ -78,13 +80,7 @@ func Connect(self C.VALUE, account C.VALUE, warehouse C.VALUE, database C.VALUE,
|
|
78
80
|
C.rb_ivar_set(self, ERROR_IDENT, RbString(errStr))
|
79
81
|
}
|
80
82
|
rs := SnowflakeClient{db}
|
81
|
-
|
82
|
-
rbStruct := C.NewGoStruct(
|
83
|
-
rbSnowflakeClientClass,
|
84
|
-
ptr,
|
85
|
-
)
|
86
|
-
|
87
|
-
C.rb_ivar_set(self, DB_IDENTIFIER, rbStruct)
|
83
|
+
clientRef[self] = &rs
|
88
84
|
}
|
89
85
|
|
90
86
|
func (x SnowflakeClient) Fetch(statement C.VALUE) C.VALUE {
|
@@ -113,46 +109,28 @@ func (x SnowflakeClient) Fetch(statement C.VALUE) C.VALUE {
|
|
113
109
|
}
|
114
110
|
|
115
111
|
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
C.RbGcGuard(rbStruct)
|
124
|
-
C.RbGcGuard(rbSnowflakeResultClass)
|
125
|
-
C.rb_ivar_set(result, RESULT_IDENTIFIER, rbStruct)
|
112
|
+
cols, _ := rows.Columns()
|
113
|
+
for idx, col := range cols {
|
114
|
+
col := col
|
115
|
+
cols[idx] = strings.ToLower(col)
|
116
|
+
}
|
117
|
+
rs := SnowflakeResult{rows, cols}
|
118
|
+
resultMap[result] = &rs
|
126
119
|
C.rb_ivar_set(result, RESULT_DURATION, RbNumFromDouble(C.double(duration)))
|
127
120
|
return result
|
128
121
|
}
|
129
122
|
|
130
123
|
//export ObjFetch
|
131
124
|
func ObjFetch(self C.VALUE, statement C.VALUE) C.VALUE {
|
132
|
-
|
133
|
-
q = C.rb_ivar_get(self, DB_IDENTIFIER)
|
134
|
-
|
135
|
-
req := C.GetGoStruct(q)
|
136
|
-
f := gopointer.Restore(req)
|
137
|
-
x, ok := f.(*SnowflakeClient)
|
138
|
-
if !ok {
|
139
|
-
wrapRbRaise((errors.New("cannot convert SnowflakeClient pointer in ObjFetch")))
|
140
|
-
}
|
125
|
+
x, _ := clientRef[self]
|
141
126
|
|
142
127
|
return x.Fetch(statement)
|
143
128
|
}
|
144
129
|
|
145
130
|
//export Inspect
|
146
131
|
func Inspect(self C.VALUE) C.VALUE {
|
147
|
-
|
148
|
-
|
149
|
-
return RbString("Object is not instantiated")
|
150
|
-
}
|
151
|
-
|
152
|
-
req := C.GetGoStruct(q)
|
153
|
-
f := gopointer.Restore(req)
|
154
|
-
x := f.(*SnowflakeClient)
|
155
|
-
return RbString(fmt.Sprintf("%+v", x))
|
132
|
+
x := clientRef[self]
|
133
|
+
return RbString(fmt.Sprintf("Snowflake::Client <%+v>", x))
|
156
134
|
}
|
157
135
|
|
158
136
|
//export Init_ruby_snowflake_client_ext
|
@@ -161,10 +139,20 @@ func Init_ruby_snowflake_client_ext() {
|
|
161
139
|
rbSnowflakeClientClass = C.rb_define_class_under(rbSnowflakeModule, C.CString("Client"), C.rb_cObject)
|
162
140
|
rbSnowflakeResultClass = C.rb_define_class_under(rbSnowflakeModule, C.CString("Result"), C.rb_cObject)
|
163
141
|
|
142
|
+
objects[rbSnowflakeResultClass] = true
|
143
|
+
objects[rbSnowflakeClientClass] = true
|
144
|
+
objects[rbSnowflakeModule] = true
|
145
|
+
objects[RESULT_DURATION] = true
|
146
|
+
objects[ERROR_IDENT] = true
|
147
|
+
C.RbGcGuard(RESULT_DURATION)
|
148
|
+
//C.RbGcGuard(RESULT_IDENTIFIER)
|
149
|
+
C.RbGcGuard(ERROR_IDENT)
|
150
|
+
|
164
151
|
C.rb_define_method(rbSnowflakeResultClass, C.CString("next_row"), (*[0]byte)(C.ObjNextRow), 0)
|
165
152
|
// `get_rows` is private as this can lead to SEGFAULT errors if not invoked
|
166
153
|
// with GC.disable due to undetermined issues caused by the Ruby GC.
|
167
154
|
C.rb_define_private_method(rbSnowflakeResultClass, C.CString("_get_rows"), (*[0]byte)(C.GetRows), 0)
|
155
|
+
C.rb_define_method(rbSnowflakeResultClass, C.CString("get_rows_no_enum"), (*[0]byte)(C.GetRowsNoEnum), 0)
|
168
156
|
|
169
157
|
C.rb_define_private_method(rbSnowflakeClientClass, C.CString("_connect"), (*[0]byte)(C.Connect), 7)
|
170
158
|
C.rb_define_method(rbSnowflakeClientClass, C.CString("inspect"), (*[0]byte)(C.Inspect), 0)
|
data/ext/wrapper.go
CHANGED
@@ -24,7 +24,7 @@ VALUE RbNumFromLong(long v) {
|
|
24
24
|
return LONG2NUM(v);
|
25
25
|
}
|
26
26
|
|
27
|
-
void goobj_retain(void *);
|
27
|
+
void goobj_retain(void *, char*);
|
28
28
|
void goobj_free(void *);
|
29
29
|
void goobj_log(void *);
|
30
30
|
void goobj_mark(void *);
|
@@ -42,9 +42,9 @@ static const rb_data_type_t go_type = {
|
|
42
42
|
};
|
43
43
|
|
44
44
|
VALUE
|
45
|
-
NewGoStruct(VALUE klass, void *p)
|
45
|
+
NewGoStruct(VALUE klass, char* reason, void *p)
|
46
46
|
{
|
47
|
-
goobj_retain(p);
|
47
|
+
goobj_retain(p, reason);
|
48
48
|
return TypedData_Wrap_Struct(klass, &go_type, p);
|
49
49
|
}
|
50
50
|
|
@@ -125,7 +125,8 @@ func RbString(str string) C.VALUE {
|
|
125
125
|
if len(str) == 0 {
|
126
126
|
return C.rb_utf8_str_new(nil, C.long(0))
|
127
127
|
}
|
128
|
-
cstr := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&str)))[0]))
|
128
|
+
//cstr := (*C.char)(unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&str)))[0]))
|
129
|
+
cstr := C.CString(str)
|
129
130
|
return C.rb_utf8_str_new(cstr, C.long(len(str)))
|
130
131
|
}
|
131
132
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Snowflake
|
4
4
|
require "ruby_snowflake_client_ext" # build bundle of the go files
|
5
|
+
LOG_LEVEL = 0
|
5
6
|
|
6
7
|
class Error < StandardError
|
7
8
|
attr_reader :details
|
@@ -51,13 +52,24 @@ module Snowflake
|
|
51
52
|
def get_all_rows(&blk)
|
52
53
|
GC.disable
|
53
54
|
if blk
|
54
|
-
|
55
|
+
while r = next_row do
|
56
|
+
yield r
|
57
|
+
end
|
55
58
|
else
|
56
|
-
|
59
|
+
get_rows_array
|
57
60
|
end
|
58
61
|
ensure
|
59
62
|
GC.enable
|
60
|
-
GC.start
|
61
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def get_rows_array
|
67
|
+
arr = []
|
68
|
+
while r = next_row do
|
69
|
+
puts "at #{arr.length}" if arr.length % 15000 == 0 && LOG_LEVEL > 0
|
70
|
+
arr << r
|
71
|
+
end
|
72
|
+
arr
|
73
|
+
end
|
62
74
|
end
|
63
75
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_snowflake_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rinsed
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-06-
|
11
|
+
date: 2023-06-09 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |
|
14
14
|
Using the `Go` library for Snowflake to query and creating native Ruby objects,
|