ruby_snowflake_client 1.1.0 → 1.2.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/.github/workflows/ci.yml +1 -1
- data/Gemfile.lock +1 -1
- data/ext/client.go +98 -0
- data/ext/result.go +6 -2
- data/ext/ruby_snowflake.go +0 -92
- data/ext/wrapper.go +0 -47
- data/lib/ruby_snowflake_client/version.rb +1 -1
- data/lib/ruby_snowflake_client.rb +4 -2
- metadata +3 -3
- data/ext/c-decl.go +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 056a78a20053733ca15070ef4aec126052ad1b6eb1c3191788ffcae8acc4d80c
|
4
|
+
data.tar.gz: 3e33de5630c3f14f3b43e8076c672cbfa47295a28a9fc740f853a7b2dbbdb07e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 215d13f6351cb22543bf1c3e356df1c98fb87e6bb2ecd2a99915a593e91316f8162e67dcce3d3e26d1135a7adf6de2538f4d2635a9bf53daf7532134e6f9a93f
|
7
|
+
data.tar.gz: 8c3b9d2a94d4641f96472ec923996940d1e7b99cf5f32989e0b3db431e046de23ec22009a0ce2a1002b3c5976484bea62de421d3c26de08af01de96de3bc0f09
|
data/.github/workflows/ci.yml
CHANGED
@@ -32,7 +32,7 @@ jobs:
|
|
32
32
|
### limits ssh access and adds the ssh public key for the user which triggered the workflow
|
33
33
|
#limit-access-to-actor: true
|
34
34
|
- name: Install gem
|
35
|
-
run: cd pkg && gem install --local *.gem
|
35
|
+
run: cd pkg && gem install --local *.gem
|
36
36
|
- name: Run tests
|
37
37
|
run: ruby -rruby_snowflake_client -S rspec spec/**/*_spec.rb -cfdoc
|
38
38
|
env: # Or as an environment variable
|
data/Gemfile.lock
CHANGED
data/ext/client.go
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
package main
|
2
|
+
|
3
|
+
/*
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include "ruby/ruby.h"
|
6
|
+
|
7
|
+
void RbGcGuard(VALUE ptr);
|
8
|
+
VALUE ReturnEnumerator(VALUE cls);
|
9
|
+
VALUE RbNumFromDouble(double v);
|
10
|
+
*/
|
11
|
+
import "C"
|
12
|
+
|
13
|
+
import (
|
14
|
+
"context"
|
15
|
+
"database/sql"
|
16
|
+
"fmt"
|
17
|
+
"strings"
|
18
|
+
"time"
|
19
|
+
|
20
|
+
sf "github.com/snowflakedb/gosnowflake"
|
21
|
+
)
|
22
|
+
|
23
|
+
type SnowflakeClient struct {
|
24
|
+
db *sql.DB
|
25
|
+
}
|
26
|
+
|
27
|
+
func (x SnowflakeClient) Fetch(statement C.VALUE) C.VALUE {
|
28
|
+
t1 := time.Now()
|
29
|
+
|
30
|
+
if LOG_LEVEL > 0 {
|
31
|
+
fmt.Println("statement", RbGoString(statement))
|
32
|
+
}
|
33
|
+
rows, err := x.db.QueryContext(sf.WithHigherPrecision(context.Background()), RbGoString(statement))
|
34
|
+
if err != nil {
|
35
|
+
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
36
|
+
errStr := fmt.Sprintf("Query error: '%s'", err.Error())
|
37
|
+
C.rb_ivar_set(result, ERROR_IDENT, RbString(errStr))
|
38
|
+
return result
|
39
|
+
}
|
40
|
+
|
41
|
+
duration := time.Now().Sub(t1).Seconds()
|
42
|
+
if LOG_LEVEL > 0 {
|
43
|
+
fmt.Printf("Query duration: %s\n", time.Now().Sub(t1))
|
44
|
+
}
|
45
|
+
if err != nil {
|
46
|
+
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
47
|
+
errStr := fmt.Sprintf("Query error: '%s'", err.Error())
|
48
|
+
C.rb_ivar_set(result, ERROR_IDENT, RbString(errStr))
|
49
|
+
return result
|
50
|
+
}
|
51
|
+
|
52
|
+
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
53
|
+
cols, _ := rows.Columns()
|
54
|
+
for idx, col := range cols {
|
55
|
+
col := col
|
56
|
+
cols[idx] = strings.ToLower(col)
|
57
|
+
}
|
58
|
+
rs := SnowflakeResult{rows, cols}
|
59
|
+
resultMap[result] = &rs
|
60
|
+
C.rb_ivar_set(result, RESULT_DURATION, RbNumFromDouble(C.double(duration)))
|
61
|
+
return result
|
62
|
+
}
|
63
|
+
|
64
|
+
//export Connect
|
65
|
+
func Connect(self C.VALUE, account C.VALUE, warehouse C.VALUE, database C.VALUE, schema C.VALUE, user C.VALUE, password C.VALUE, role C.VALUE) {
|
66
|
+
// other optional parms: Application, Host, and alt auth schemes
|
67
|
+
cfg := &sf.Config{
|
68
|
+
Account: RbGoString(account),
|
69
|
+
Warehouse: RbGoString(warehouse),
|
70
|
+
Database: RbGoString(database),
|
71
|
+
Schema: RbGoString(schema),
|
72
|
+
User: RbGoString(user),
|
73
|
+
Password: RbGoString(password),
|
74
|
+
Role: RbGoString(role),
|
75
|
+
Port: int(443),
|
76
|
+
}
|
77
|
+
|
78
|
+
dsn, err := sf.DSN(cfg)
|
79
|
+
if err != nil {
|
80
|
+
errStr := fmt.Sprintf("Snowflake Config Creation Error: '%s'", err.Error())
|
81
|
+
C.rb_ivar_set(self, ERROR_IDENT, RbString(errStr))
|
82
|
+
}
|
83
|
+
|
84
|
+
db, err := sql.Open("snowflake", dsn)
|
85
|
+
if err != nil {
|
86
|
+
errStr := fmt.Sprintf("Connection Error: '%s'", err.Error())
|
87
|
+
C.rb_ivar_set(self, ERROR_IDENT, RbString(errStr))
|
88
|
+
}
|
89
|
+
rs := SnowflakeClient{db}
|
90
|
+
clientRef[self] = &rs
|
91
|
+
}
|
92
|
+
|
93
|
+
//export ObjFetch
|
94
|
+
func ObjFetch(self C.VALUE, statement C.VALUE) C.VALUE {
|
95
|
+
x, _ := clientRef[self]
|
96
|
+
|
97
|
+
return x.Fetch(statement)
|
98
|
+
}
|
data/ext/result.go
CHANGED
@@ -5,12 +5,11 @@ package main
|
|
5
5
|
#include "ruby/ruby.h"
|
6
6
|
|
7
7
|
VALUE ReturnEnumerator(VALUE cls);
|
8
|
-
VALUE createRbString(char* str);
|
9
|
-
VALUE funcall0param(VALUE obj, ID id);
|
10
8
|
*/
|
11
9
|
import "C"
|
12
10
|
|
13
11
|
import (
|
12
|
+
"database/sql"
|
14
13
|
"fmt"
|
15
14
|
"math/big"
|
16
15
|
"time"
|
@@ -18,6 +17,11 @@ import (
|
|
18
17
|
gopointer "github.com/mattn/go-pointer"
|
19
18
|
)
|
20
19
|
|
20
|
+
type SnowflakeResult struct {
|
21
|
+
rows *sql.Rows
|
22
|
+
columns []string
|
23
|
+
}
|
24
|
+
|
21
25
|
func wrapRbRaise(err error) {
|
22
26
|
fmt.Printf("[ruby-snowflake-client] Error encountered: %s\n", err.Error())
|
23
27
|
fmt.Printf("[ruby-snowflake-client] Will call `rb_raise`\n")
|
data/ext/ruby_snowflake.go
CHANGED
@@ -10,9 +10,6 @@ VALUE Inspect(VALUE);
|
|
10
10
|
VALUE GetRows(VALUE);
|
11
11
|
VALUE GetRowsNoEnum(VALUE);
|
12
12
|
|
13
|
-
VALUE NewGoStruct(VALUE klass, char* reason, void *p);
|
14
|
-
VALUE GoRetEnum(VALUE,int,VALUE);
|
15
|
-
void* GetGoStruct(VALUE obj);
|
16
13
|
void RbGcGuard(VALUE ptr);
|
17
14
|
VALUE ReturnEnumerator(VALUE cls);
|
18
15
|
VALUE RbNumFromDouble(double v);
|
@@ -20,25 +17,9 @@ VALUE RbNumFromDouble(double v);
|
|
20
17
|
import "C"
|
21
18
|
|
22
19
|
import (
|
23
|
-
"context"
|
24
|
-
"database/sql"
|
25
20
|
"fmt"
|
26
|
-
"strings"
|
27
|
-
"time"
|
28
|
-
|
29
|
-
sf "github.com/snowflakedb/gosnowflake"
|
30
21
|
)
|
31
22
|
|
32
|
-
type SnowflakeResult struct {
|
33
|
-
rows *sql.Rows
|
34
|
-
//keptHash C.VALUE
|
35
|
-
columns []string
|
36
|
-
//cols []C.VALUE
|
37
|
-
}
|
38
|
-
type SnowflakeClient struct {
|
39
|
-
db *sql.DB
|
40
|
-
}
|
41
|
-
|
42
23
|
var rbSnowflakeClientClass C.VALUE
|
43
24
|
var rbSnowflakeResultClass C.VALUE
|
44
25
|
var rbSnowflakeModule C.VALUE
|
@@ -54,79 +35,6 @@ var clientRef = make(map[C.VALUE]*SnowflakeClient)
|
|
54
35
|
var LOG_LEVEL = 0
|
55
36
|
var empty C.VALUE = C.Qnil
|
56
37
|
|
57
|
-
//export Connect
|
58
|
-
func Connect(self C.VALUE, account C.VALUE, warehouse C.VALUE, database C.VALUE, schema C.VALUE, user C.VALUE, password C.VALUE, role C.VALUE) {
|
59
|
-
// other optional parms: Application, Host, and alt auth schemes
|
60
|
-
cfg := &sf.Config{
|
61
|
-
Account: RbGoString(account),
|
62
|
-
Warehouse: RbGoString(warehouse),
|
63
|
-
Database: RbGoString(database),
|
64
|
-
Schema: RbGoString(schema),
|
65
|
-
User: RbGoString(user),
|
66
|
-
Password: RbGoString(password),
|
67
|
-
Role: RbGoString(role),
|
68
|
-
Port: int(443),
|
69
|
-
}
|
70
|
-
|
71
|
-
dsn, err := sf.DSN(cfg)
|
72
|
-
if err != nil {
|
73
|
-
errStr := fmt.Sprintf("Snowflake Config Creation Error: '%s'", err.Error())
|
74
|
-
C.rb_ivar_set(self, ERROR_IDENT, RbString(errStr))
|
75
|
-
}
|
76
|
-
|
77
|
-
db, err := sql.Open("snowflake", dsn)
|
78
|
-
if err != nil {
|
79
|
-
errStr := fmt.Sprintf("Connection Error: '%s'", err.Error())
|
80
|
-
C.rb_ivar_set(self, ERROR_IDENT, RbString(errStr))
|
81
|
-
}
|
82
|
-
rs := SnowflakeClient{db}
|
83
|
-
clientRef[self] = &rs
|
84
|
-
}
|
85
|
-
|
86
|
-
func (x SnowflakeClient) Fetch(statement C.VALUE) C.VALUE {
|
87
|
-
t1 := time.Now()
|
88
|
-
|
89
|
-
if LOG_LEVEL > 0 {
|
90
|
-
fmt.Println("statement", RbGoString(statement))
|
91
|
-
}
|
92
|
-
rows, err := x.db.QueryContext(sf.WithHigherPrecision(context.Background()), RbGoString(statement))
|
93
|
-
if err != nil {
|
94
|
-
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
95
|
-
errStr := fmt.Sprintf("Query error: '%s'", err.Error())
|
96
|
-
C.rb_ivar_set(result, ERROR_IDENT, RbString(errStr))
|
97
|
-
return result
|
98
|
-
}
|
99
|
-
|
100
|
-
duration := time.Now().Sub(t1).Seconds()
|
101
|
-
if LOG_LEVEL > 0 {
|
102
|
-
fmt.Printf("Query duration: %s\n", time.Now().Sub(t1))
|
103
|
-
}
|
104
|
-
if err != nil {
|
105
|
-
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
106
|
-
errStr := fmt.Sprintf("Query error: '%s'", err.Error())
|
107
|
-
C.rb_ivar_set(result, ERROR_IDENT, RbString(errStr))
|
108
|
-
return result
|
109
|
-
}
|
110
|
-
|
111
|
-
result := C.rb_class_new_instance(0, &empty, rbSnowflakeResultClass)
|
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
|
119
|
-
C.rb_ivar_set(result, RESULT_DURATION, RbNumFromDouble(C.double(duration)))
|
120
|
-
return result
|
121
|
-
}
|
122
|
-
|
123
|
-
//export ObjFetch
|
124
|
-
func ObjFetch(self C.VALUE, statement C.VALUE) C.VALUE {
|
125
|
-
x, _ := clientRef[self]
|
126
|
-
|
127
|
-
return x.Fetch(statement)
|
128
|
-
}
|
129
|
-
|
130
38
|
//export Inspect
|
131
39
|
func Inspect(self C.VALUE) C.VALUE {
|
132
40
|
x := clientRef[self]
|
data/ext/wrapper.go
CHANGED
@@ -24,57 +24,14 @@ VALUE RbNumFromLong(long v) {
|
|
24
24
|
return LONG2NUM(v);
|
25
25
|
}
|
26
26
|
|
27
|
-
void goobj_retain(void *, char*);
|
28
|
-
void goobj_free(void *);
|
29
|
-
void goobj_log(void *);
|
30
|
-
void goobj_mark(void *);
|
31
|
-
void goobj_compact(void *);
|
32
|
-
|
33
|
-
static const rb_data_type_t go_type = {
|
34
|
-
"GoStruct",
|
35
|
-
{
|
36
|
-
goobj_mark,
|
37
|
-
goobj_free,
|
38
|
-
NULL,
|
39
|
-
(goobj_compact),
|
40
|
-
},
|
41
|
-
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
42
|
-
};
|
43
|
-
|
44
|
-
VALUE
|
45
|
-
NewGoStruct(VALUE klass, char* reason, void *p)
|
46
|
-
{
|
47
|
-
goobj_retain(p, reason);
|
48
|
-
return TypedData_Wrap_Struct(klass, &go_type, p);
|
49
|
-
}
|
50
|
-
|
51
27
|
VALUE ReturnEnumerator(VALUE cls) {
|
52
28
|
RETURN_ENUMERATOR(cls, 0, NULL);
|
53
29
|
return Qnil;
|
54
30
|
}
|
55
31
|
|
56
|
-
void *
|
57
|
-
GetGoStruct(VALUE obj)
|
58
|
-
{
|
59
|
-
void *val;
|
60
|
-
return TypedData_Get_Struct(obj, void *, &go_type, val);
|
61
|
-
}
|
62
|
-
|
63
32
|
void RbGcGuard(VALUE ptr) {
|
64
33
|
RB_GC_GUARD(ptr);
|
65
34
|
}
|
66
|
-
|
67
|
-
VALUE createRbString(char* str) {
|
68
|
-
volatile VALUE rbStr;
|
69
|
-
rbStr = rb_tainted_str_new_cstr(str);
|
70
|
-
return rbStr;
|
71
|
-
}
|
72
|
-
|
73
|
-
VALUE funcall0param(VALUE obj, ID id) {
|
74
|
-
RB_GC_GUARD(obj);
|
75
|
-
return rb_funcall(obj, id, 0);
|
76
|
-
}
|
77
|
-
|
78
35
|
*/
|
79
36
|
import "C"
|
80
37
|
import (
|
@@ -90,10 +47,6 @@ func RbNumFromDouble(v C.double) C.VALUE {
|
|
90
47
|
return C.RbNumFromDouble(v)
|
91
48
|
}
|
92
49
|
|
93
|
-
func GetGoStruct(obj C.VALUE) unsafe.Pointer {
|
94
|
-
return C.GetGoStruct(obj)
|
95
|
-
}
|
96
|
-
|
97
50
|
func returnEnum(cls C.VALUE) C.VALUE {
|
98
51
|
return C.ReturnEnumerator(cls)
|
99
52
|
}
|
@@ -5,10 +5,12 @@ module Snowflake
|
|
5
5
|
LOG_LEVEL = 0
|
6
6
|
|
7
7
|
class Error < StandardError
|
8
|
-
|
8
|
+
# This will get pulled through to Sentry, see:
|
9
|
+
# https://github.com/getsentry/sentry-ruby/blob/11ecd254c0d2cae2b327f0348074e849095aa32d/sentry-ruby/lib/sentry/error_event.rb#L31-L33
|
10
|
+
attr_reader :sentry_context
|
9
11
|
|
10
12
|
def initialize(details)
|
11
|
-
@
|
13
|
+
@sentry_context = details
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
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.
|
4
|
+
version: 1.2.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-26 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,
|
@@ -29,7 +29,7 @@ files:
|
|
29
29
|
- LICENSE.txt
|
30
30
|
- README.md
|
31
31
|
- Rakefile
|
32
|
-
- ext/
|
32
|
+
- ext/client.go
|
33
33
|
- ext/extconf.rb
|
34
34
|
- ext/go.mod
|
35
35
|
- ext/go.sum
|
data/ext/c-decl.go
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
package main
|
2
|
-
|
3
|
-
/*
|
4
|
-
#include <stdlib.h>
|
5
|
-
#include "ruby/ruby.h"
|
6
|
-
*/
|
7
|
-
import "C"
|
8
|
-
|
9
|
-
import (
|
10
|
-
"fmt"
|
11
|
-
"unsafe"
|
12
|
-
)
|
13
|
-
|
14
|
-
var marked = make(map[unsafe.Pointer]int)
|
15
|
-
|
16
|
-
//export goobj_mark
|
17
|
-
func goobj_mark(obj unsafe.Pointer) {
|
18
|
-
if LOG_LEVEL > 0 {
|
19
|
-
marked[obj] = marked[obj] + 1
|
20
|
-
fmt.Printf("MARK log obj %v; counter: %d; total number of MARKED objects: %d\n", obj, marked[obj], len(marked))
|
21
|
-
}
|
22
|
-
}
|
23
|
-
|
24
|
-
//export goobj_log
|
25
|
-
func goobj_log(obj unsafe.Pointer) {
|
26
|
-
if LOG_LEVEL > 0 {
|
27
|
-
fmt.Println("log obj", obj)
|
28
|
-
}
|
29
|
-
}
|
30
|
-
|
31
|
-
//export goobj_retain
|
32
|
-
func goobj_retain(obj unsafe.Pointer, x *C.char) {
|
33
|
-
if LOG_LEVEL > 0 {
|
34
|
-
fmt.Printf("retain obj [%v] %v - currently keeping %d\n", C.GoString(x), obj, len(objects))
|
35
|
-
}
|
36
|
-
objects[obj] = true
|
37
|
-
marked[obj] = 0
|
38
|
-
}
|
39
|
-
|
40
|
-
//export goobj_free
|
41
|
-
func goobj_free(obj unsafe.Pointer) {
|
42
|
-
if LOG_LEVEL > 0 {
|
43
|
-
fmt.Printf("CALLED GOOBJ FREE %v - CURRENTLY %d objects left\n", obj, len(objects))
|
44
|
-
}
|
45
|
-
delete(objects, obj)
|
46
|
-
delete(marked, obj)
|
47
|
-
}
|
48
|
-
|
49
|
-
//export goobj_compact
|
50
|
-
func goobj_compact(obj unsafe.Pointer) {
|
51
|
-
if LOG_LEVEL > 0 {
|
52
|
-
fmt.Printf("CALLED GOOBJ COMPACT %v", obj)
|
53
|
-
}
|
54
|
-
}
|