ruby_snowflake_client 1.0.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e0c56fd4b0b95f40bbd1ed55dc9fb10bc6284ac198b527b3dfa977f2419fa5f
4
- data.tar.gz: 9351e25573c2553ec2ab6123df8d829e53749ee25e5c6a82de9d4c1e7ca65c4e
3
+ metadata.gz: 75899b8f6ba98da01620d76f6d7077ba73ae8dd7fb1177815300b969d0dbf7b5
4
+ data.tar.gz: 2fdbd266149c69bf17d59c83ab09418ca8f46d23707c5c3d98cc8e6800bf84e2
5
5
  SHA512:
6
- metadata.gz: d414d31259999434fc6323be3fb41a3d1fa854fccad0a09902885bab19e5ed5c68e921d1ca254baaf2cf11f46e91b1fcb9c66f6656f0130798774e5b95f44f48
7
- data.tar.gz: a4e515cdf374ca890ba03ca04602c10f0382bf4768d626d03d50a9febf26f8930bc294a56e8447290bd4677163521c35f9fded4dd81d7741f0d1bb087507c751
6
+ metadata.gz: 180122aebc707aeda9e7cff2fad9ab6361b21d027b4dc23961bb64319ae192338091fff3b5600cbc15a86522c39bff2b4402723c7c0dfbd80570bdea3e3f96cb
7
+ data.tar.gz: 65ab2555c42a044224ee1f5e010f43f7ddc9491205d271bd4459459ee5ffb3f65112bd310742c1bcab797c66e8a590e96f732032142ba3866e2e91afb5feb40b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby_snowflake_client (1.0.2)
4
+ ruby_snowflake_client (1.1.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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
- ivar := C.rb_ivar_get(self, RESULT_IDENTIFIER)
28
+ return resultMap[self]
29
+ }
32
30
 
33
- str := GetGoStruct(ivar)
34
- ptr := gopointer.Restore(str)
35
- sr, ok := ptr.(*SnowflakeResult)
36
- if !ok || sr.rows == nil {
37
- err := errors.New("Empty result; please run a query via `client.fetch(\"SQL\")`")
38
- wrapRbRaise(err)
39
- return nil
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
- return sr
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.cols))
108
- rawData := make([]any, len(res.cols))
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.rb_hash_aset(hash, col_name, rbVal)
155
- }
156
- return hash
157
- }
158
-
159
- func SafeMakeHash(lenght int, cols []C.VALUE) C.VALUE {
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
- }
@@ -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 *sql.Rows
34
- keptHash C.VALUE
35
- cols []C.VALUE
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
- ptr := gopointer.Save(&rs)
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
- rs := SnowflakeResult{rows, C.Qnil, []C.VALUE{}}
117
- rs.Initialize()
118
- ptr := gopointer.Save(&rs)
119
- rbStruct := C.NewGoStruct(
120
- rbSnowflakeClientClass,
121
- ptr,
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
- var q C.VALUE
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
- q := C.rb_ivar_get(self, DB_IDENTIFIER)
148
- if q == C.Qnil {
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
 
@@ -1,3 +1,3 @@
1
1
  module RubySnowflakeClient
2
- VERSION = '1.0.2'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -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
- _get_rows(&blk)
55
+ while r = next_row do
56
+ yield r
57
+ end
55
58
  else
56
- _get_rows.to_a
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.2
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-08 00:00:00.000000000 Z
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,