ruby-ladybug 0.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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/History.md +9 -0
- data/LICENSE.txt +20 -0
- data/README.md +250 -0
- data/ext/ladybug_ext/config.c +318 -0
- data/ext/ladybug_ext/connection.c +331 -0
- data/ext/ladybug_ext/database.c +197 -0
- data/ext/ladybug_ext/extconf.rb +20 -0
- data/ext/ladybug_ext/ladybug_ext.c +158 -0
- data/ext/ladybug_ext/ladybug_ext.h +132 -0
- data/ext/ladybug_ext/node.c +24 -0
- data/ext/ladybug_ext/prepared_statement.c +396 -0
- data/ext/ladybug_ext/query_summary.c +140 -0
- data/ext/ladybug_ext/recursive_rel.c +24 -0
- data/ext/ladybug_ext/rel.c +24 -0
- data/ext/ladybug_ext/result.c +514 -0
- data/ext/ladybug_ext/types.c +619 -0
- data/lib/ladybug/config.rb +70 -0
- data/lib/ladybug/connection.rb +51 -0
- data/lib/ladybug/database.rb +53 -0
- data/lib/ladybug/node.rb +46 -0
- data/lib/ladybug/prepared_statement.rb +44 -0
- data/lib/ladybug/query_summary.rb +28 -0
- data/lib/ladybug/recursive_rel.rb +37 -0
- data/lib/ladybug/rel.rb +57 -0
- data/lib/ladybug/result.rb +196 -0
- data/lib/ladybug.rb +89 -0
- data/spec/ladybug/config_spec.rb +98 -0
- data/spec/ladybug/connection_spec.rb +36 -0
- data/spec/ladybug/database_spec.rb +57 -0
- data/spec/ladybug/prepared_statement_spec.rb +91 -0
- data/spec/ladybug/query_summary_spec.rb +30 -0
- data/spec/ladybug/result_spec.rb +225 -0
- data/spec/ladybug/types_spec.rb +285 -0
- data/spec/ladybug_spec.rb +83 -0
- data/spec/spec_helper.rb +101 -0
- data.tar.gz.sig +0 -0
- metadata +177 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* connection.c - Ladybug::Connection class
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "lbug.h"
|
|
7
|
+
#include "ladybug_ext.h"
|
|
8
|
+
#include "ruby/thread.h"
|
|
9
|
+
|
|
10
|
+
#define CHECK_CONNECTION(self) ((rlbug_connection *)rb_check_typeddata((self), &rlbug_connection_type))
|
|
11
|
+
// #define DEBUG_GC(msg, ptr) fprintf( stderr, msg, ptr )
|
|
12
|
+
#define DEBUG_GC(msg, ptr)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
VALUE rlbug_cLadybugConnection;
|
|
16
|
+
|
|
17
|
+
static void rlbug_connection_free( void * );
|
|
18
|
+
static void rlbug_connection_mark( void * );
|
|
19
|
+
|
|
20
|
+
static const rb_data_type_t rlbug_connection_type = {
|
|
21
|
+
.wrap_struct_name = "Ladybug::Connection",
|
|
22
|
+
.function = {
|
|
23
|
+
.dfree = rlbug_connection_free,
|
|
24
|
+
.dmark = rlbug_connection_mark,
|
|
25
|
+
},
|
|
26
|
+
.data = NULL,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
rlbug_connection *
|
|
31
|
+
rlbug_get_connection( VALUE conn_obj )
|
|
32
|
+
{
|
|
33
|
+
return CHECK_CONNECTION( conn_obj );
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
static rlbug_connection *
|
|
38
|
+
rlbug_connection_alloc( void )
|
|
39
|
+
{
|
|
40
|
+
rlbug_connection *ptr = ALLOC( rlbug_connection );
|
|
41
|
+
|
|
42
|
+
ptr->database = Qnil;
|
|
43
|
+
ptr->queries = rb_ary_new();
|
|
44
|
+
ptr->statements = rb_ary_new();
|
|
45
|
+
|
|
46
|
+
return ptr;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
static void
|
|
51
|
+
rlbug_connection_free( void *ptr )
|
|
52
|
+
{
|
|
53
|
+
rlbug_connection *conn_s = (rlbug_connection *)ptr;
|
|
54
|
+
|
|
55
|
+
if ( ptr ) {
|
|
56
|
+
DEBUG_GC( ">>> freeing connection %p\n", ptr );
|
|
57
|
+
|
|
58
|
+
lbug_connection_destroy( &conn_s->conn );
|
|
59
|
+
|
|
60
|
+
xfree( ptr );
|
|
61
|
+
ptr = NULL;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
static void
|
|
67
|
+
rlbug_connection_mark( void *ptr )
|
|
68
|
+
{
|
|
69
|
+
rlbug_connection *conn_s = (rlbug_connection *)ptr;
|
|
70
|
+
|
|
71
|
+
if ( ptr ) {
|
|
72
|
+
DEBUG_GC( ">>> marking connection %p\n", ptr );
|
|
73
|
+
rb_gc_mark( conn_s->database );
|
|
74
|
+
rb_gc_mark( conn_s->statements );
|
|
75
|
+
rb_gc_mark( conn_s->queries );
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* ::allocate function
|
|
82
|
+
*/
|
|
83
|
+
static VALUE
|
|
84
|
+
rlbug_connection_s_allocate( VALUE klass )
|
|
85
|
+
{
|
|
86
|
+
return TypedData_Wrap_Struct( klass, &rlbug_connection_type, NULL );
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* call-seq:
|
|
93
|
+
* new( database ) -> connection
|
|
94
|
+
*
|
|
95
|
+
* Create a Ladybug::Connection to the specified +database+.
|
|
96
|
+
*
|
|
97
|
+
*/
|
|
98
|
+
static VALUE
|
|
99
|
+
rlbug_connection_initialize( VALUE self, VALUE database )
|
|
100
|
+
{
|
|
101
|
+
rlbug_connection *ptr = CHECK_CONNECTION( self );
|
|
102
|
+
|
|
103
|
+
if ( !ptr ) {
|
|
104
|
+
rlbug_database *dbobject = rlbug_get_database( database );
|
|
105
|
+
ptr = rlbug_connection_alloc();
|
|
106
|
+
|
|
107
|
+
if ( lbug_connection_init(&dbobject->db, &ptr->conn) != LbugSuccess ) {
|
|
108
|
+
xfree( ptr );
|
|
109
|
+
ptr = NULL;
|
|
110
|
+
rb_raise( rlbug_eConnectionError, "Failed to connect!" );
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
DEBUG_GC( ">>> allocated connection %p\n", ptr );
|
|
114
|
+
RTYPEDDATA_DATA( self ) = ptr;
|
|
115
|
+
|
|
116
|
+
ptr->database = database;
|
|
117
|
+
|
|
118
|
+
} else {
|
|
119
|
+
rb_raise( rb_eRuntimeError, "cannot reinit connection" );
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
rb_call_super( 0, 0 );
|
|
123
|
+
|
|
124
|
+
return Qtrue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
struct query_call {
|
|
129
|
+
lbug_connection *conn;
|
|
130
|
+
const char *query_s;
|
|
131
|
+
lbug_query_result *result;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
static void *
|
|
136
|
+
rlbug_connection_do_query_without_gvl( void *ptr )
|
|
137
|
+
{
|
|
138
|
+
struct query_call *qcall = (struct query_call *)ptr;
|
|
139
|
+
lbug_state state;
|
|
140
|
+
|
|
141
|
+
state = lbug_connection_query( qcall->conn, qcall->query_s, qcall->result );
|
|
142
|
+
|
|
143
|
+
return (void *)state;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
static void
|
|
148
|
+
rlbug_connection_cancel_query( void *ptr )
|
|
149
|
+
{
|
|
150
|
+
lbug_connection *conn = (lbug_connection *)ptr;
|
|
151
|
+
lbug_connection_interrupt( conn );
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
static lbug_query_result
|
|
156
|
+
rlbug_connection_do_query( VALUE self, VALUE query )
|
|
157
|
+
{
|
|
158
|
+
rlbug_connection *conn = CHECK_CONNECTION( self );
|
|
159
|
+
const char *query_s = StringValueCStr( query );
|
|
160
|
+
lbug_query_result result;
|
|
161
|
+
lbug_state query_state;
|
|
162
|
+
struct query_call qcall;
|
|
163
|
+
void *result_ptr;
|
|
164
|
+
|
|
165
|
+
qcall.conn = &conn->conn;
|
|
166
|
+
qcall.query_s = query_s;
|
|
167
|
+
qcall.result = &result;
|
|
168
|
+
|
|
169
|
+
result_ptr = rb_thread_call_without_gvl(
|
|
170
|
+
rlbug_connection_do_query_without_gvl, (void *)&qcall,
|
|
171
|
+
rlbug_connection_cancel_query, (void *)&conn->conn );
|
|
172
|
+
|
|
173
|
+
_Pragma("GCC diagnostic push")
|
|
174
|
+
_Pragma("GCC diagnostic ignored \"-Wvoid-pointer-to-enum-cast\"")
|
|
175
|
+
query_state = (lbug_state)result_ptr;
|
|
176
|
+
_Pragma("GCC diagnostic pop")
|
|
177
|
+
|
|
178
|
+
if ( query_state != LbugSuccess ) {
|
|
179
|
+
char *err_detail = lbug_query_result_get_error_message( &result );
|
|
180
|
+
char errmsg[ 4096 ] = "\0";
|
|
181
|
+
|
|
182
|
+
snprintf( errmsg, 4096, "Could not execute query `%s': %s.", query_s, err_detail );
|
|
183
|
+
|
|
184
|
+
lbug_destroy_string( err_detail );
|
|
185
|
+
lbug_query_result_destroy( &result );
|
|
186
|
+
|
|
187
|
+
rb_raise( rlbug_eQueryError, "%s", errmsg );
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return *qcall.result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
static VALUE
|
|
196
|
+
rlbug_connection__query( VALUE self, VALUE query )
|
|
197
|
+
{
|
|
198
|
+
lbug_query_result result = rlbug_connection_do_query( self, query );
|
|
199
|
+
return rlbug_result_from_query( rlbug_cLadybugResult, self, query, result );
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
/*
|
|
204
|
+
* call-seq:
|
|
205
|
+
* connection.query!( query_string )
|
|
206
|
+
*
|
|
207
|
+
* Execute the given +query_string+ and return `true` if the query was
|
|
208
|
+
* successful.
|
|
209
|
+
*
|
|
210
|
+
*/
|
|
211
|
+
static VALUE
|
|
212
|
+
rlbug_connection_query_bang( VALUE self, VALUE query )
|
|
213
|
+
{
|
|
214
|
+
lbug_query_result result = rlbug_connection_do_query( self, query );
|
|
215
|
+
return lbug_query_result_is_success( &result ) ? Qtrue : Qfalse;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
/*
|
|
220
|
+
* call-seq:
|
|
221
|
+
* connection.max_num_threads_for_exec -> integer
|
|
222
|
+
*
|
|
223
|
+
* Returns the maximum number of threads of the connection to use for
|
|
224
|
+
* executing queries.
|
|
225
|
+
*
|
|
226
|
+
*/
|
|
227
|
+
static VALUE
|
|
228
|
+
rlbug_connection_max_num_threads_for_exec( VALUE self )
|
|
229
|
+
{
|
|
230
|
+
rlbug_connection *ptr = CHECK_CONNECTION( self );
|
|
231
|
+
uint64_t count;
|
|
232
|
+
|
|
233
|
+
if ( lbug_connection_get_max_num_thread_for_exec( &ptr->conn, &count ) != LbugSuccess ) {
|
|
234
|
+
rb_raise( rlbug_eError, "lbug_connection_get_max_num_thread_for_exec failed" );
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return ULONG2NUM( count );
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
/*
|
|
242
|
+
* call-seq:
|
|
243
|
+
* connection.max_num_threads_for_exec = integer
|
|
244
|
+
*
|
|
245
|
+
* Sets the maximum number of threads of the connection to use for
|
|
246
|
+
* executing queries.
|
|
247
|
+
*
|
|
248
|
+
*/
|
|
249
|
+
static VALUE
|
|
250
|
+
rlbug_connection_max_num_threads_for_exec_eq( VALUE self, VALUE count )
|
|
251
|
+
{
|
|
252
|
+
rlbug_connection *ptr = CHECK_CONNECTION( self );
|
|
253
|
+
uint64_t thread_count = NUM2ULONG( count );
|
|
254
|
+
|
|
255
|
+
if ( lbug_connection_set_max_num_thread_for_exec( &ptr->conn, thread_count ) != LbugSuccess ) {
|
|
256
|
+
rb_raise( rlbug_eError, "lbug_connection_set_max_num_thread_for_exec failed" );
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return Qtrue;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
/*
|
|
264
|
+
* call-seq:
|
|
265
|
+
* connection.query_timeout = integer
|
|
266
|
+
*
|
|
267
|
+
* Sets query timeout value in milliseconds for the connection.
|
|
268
|
+
*
|
|
269
|
+
*/
|
|
270
|
+
static VALUE
|
|
271
|
+
rlbug_connection_query_timeout_eq( VALUE self, VALUE timeout )
|
|
272
|
+
{
|
|
273
|
+
rlbug_connection *ptr = CHECK_CONNECTION( self );
|
|
274
|
+
uint64_t timeout_in_ms = NUM2ULONG( timeout );
|
|
275
|
+
|
|
276
|
+
if ( lbug_connection_set_query_timeout( &ptr->conn, timeout_in_ms ) != LbugSuccess ) {
|
|
277
|
+
rb_raise( rlbug_eError, "lbug_connection_set_query_timeout failed" );
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return Qtrue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
/*
|
|
285
|
+
* call-seq:
|
|
286
|
+
* connection.database -> database
|
|
287
|
+
*
|
|
288
|
+
* Return the database object the connection belongs to (a Ladybug::Database).
|
|
289
|
+
*
|
|
290
|
+
*/
|
|
291
|
+
static VALUE
|
|
292
|
+
rlbug_connection_database( VALUE self )
|
|
293
|
+
{
|
|
294
|
+
rlbug_connection *ptr = CHECK_CONNECTION( self );
|
|
295
|
+
return ptr->database;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
/*
|
|
301
|
+
* Document-class: Ladybug::Connection
|
|
302
|
+
*/
|
|
303
|
+
void
|
|
304
|
+
rlbug_init_connection( void )
|
|
305
|
+
{
|
|
306
|
+
#ifdef FOR_RDOC
|
|
307
|
+
rlbug_mLadybug = rb_define_module( "ladybug" );
|
|
308
|
+
#endif
|
|
309
|
+
|
|
310
|
+
rlbug_cLadybugConnection = rb_define_class_under( rlbug_mLadybug, "Connection", rb_cObject );
|
|
311
|
+
|
|
312
|
+
rb_define_alloc_func( rlbug_cLadybugConnection, rlbug_connection_s_allocate );
|
|
313
|
+
|
|
314
|
+
rb_define_protected_method( rlbug_cLadybugConnection, "initialize", rlbug_connection_initialize, 1 );
|
|
315
|
+
|
|
316
|
+
rb_define_protected_method( rlbug_cLadybugConnection, "_query", rlbug_connection__query, 1 );
|
|
317
|
+
rb_define_method( rlbug_cLadybugConnection, "query!", rlbug_connection_query_bang, 1 );
|
|
318
|
+
rb_define_alias( rlbug_cLadybugConnection, "run", "query!" );
|
|
319
|
+
|
|
320
|
+
rb_define_method( rlbug_cLadybugConnection, "max_num_threads_for_exec",
|
|
321
|
+
rlbug_connection_max_num_threads_for_exec, 0 );
|
|
322
|
+
rb_define_method( rlbug_cLadybugConnection, "max_num_threads_for_exec=",
|
|
323
|
+
rlbug_connection_max_num_threads_for_exec_eq, 1 );
|
|
324
|
+
|
|
325
|
+
rb_define_method( rlbug_cLadybugConnection, "query_timeout=", rlbug_connection_query_timeout_eq, 1 );
|
|
326
|
+
|
|
327
|
+
rb_define_method( rlbug_cLadybugConnection, "database", rlbug_connection_database, 0 );
|
|
328
|
+
rb_define_alias( rlbug_cLadybugConnection, "db", "database" );
|
|
329
|
+
|
|
330
|
+
rb_require( "ladybug/connection" );
|
|
331
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* database.c - Ladybug::Database class
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
#include "ladybug_ext.h"
|
|
6
|
+
|
|
7
|
+
#define CHECK_DATABASE(self) ((rlbug_database*)rb_check_typeddata((self), &rlbug_database_type))
|
|
8
|
+
// #define DEBUG_GC(msg, ptr) fprintf( stderr, msg, ptr )
|
|
9
|
+
#define DEBUG_GC(msg, ptr)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
VALUE rlbug_cLadybugDatabase;
|
|
13
|
+
|
|
14
|
+
static void rlbug_database_free( void * );
|
|
15
|
+
static void rlbug_database_mark( void * );
|
|
16
|
+
|
|
17
|
+
static const rb_data_type_t rlbug_database_type = {
|
|
18
|
+
.wrap_struct_name = "Ladybug::Database",
|
|
19
|
+
.function = {
|
|
20
|
+
.dmark = rlbug_database_mark,
|
|
21
|
+
.dfree = rlbug_database_free,
|
|
22
|
+
},
|
|
23
|
+
.data = NULL,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
rlbug_database *
|
|
28
|
+
rlbug_get_database( VALUE obj )
|
|
29
|
+
{
|
|
30
|
+
return CHECK_DATABASE( obj );
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/*
|
|
35
|
+
* Struct allocation/init function.
|
|
36
|
+
*/
|
|
37
|
+
static rlbug_database *
|
|
38
|
+
rlbug_database_alloc( void )
|
|
39
|
+
{
|
|
40
|
+
rlbug_database *ptr = ALLOC( rlbug_database );
|
|
41
|
+
|
|
42
|
+
ptr->path = Qnil;
|
|
43
|
+
ptr->config = Qnil;
|
|
44
|
+
|
|
45
|
+
return ptr;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Free function
|
|
51
|
+
*/
|
|
52
|
+
static void
|
|
53
|
+
rlbug_database_free( void *ptr )
|
|
54
|
+
{
|
|
55
|
+
if ( ptr ) {
|
|
56
|
+
DEBUG_GC( ">>> freeing database %p\n", ptr );
|
|
57
|
+
rlbug_database *database_s = (rlbug_database *)ptr;
|
|
58
|
+
|
|
59
|
+
lbug_database_destroy( &database_s->db );
|
|
60
|
+
|
|
61
|
+
database_s->path = Qnil;
|
|
62
|
+
database_s->config = Qnil;
|
|
63
|
+
|
|
64
|
+
xfree( ptr );
|
|
65
|
+
ptr = NULL;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* Mark function
|
|
72
|
+
*/
|
|
73
|
+
static void
|
|
74
|
+
rlbug_database_mark( void *ptr )
|
|
75
|
+
{
|
|
76
|
+
rlbug_database *database_s = (rlbug_database *)ptr;
|
|
77
|
+
|
|
78
|
+
DEBUG_GC( ">>> marking database %p\n", ptr );
|
|
79
|
+
|
|
80
|
+
rb_gc_mark( database_s->path );
|
|
81
|
+
rb_gc_mark( database_s->config );
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* ::allocate function
|
|
88
|
+
*/
|
|
89
|
+
static VALUE
|
|
90
|
+
rlbug_database_s_allocate( VALUE klass )
|
|
91
|
+
{
|
|
92
|
+
return TypedData_Wrap_Struct( klass, &rlbug_database_type, NULL );
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
* call-seq:
|
|
98
|
+
* database.new( path, **options ) -> database
|
|
99
|
+
*
|
|
100
|
+
* Create a new Database using the given +path+ and +options+.
|
|
101
|
+
*
|
|
102
|
+
*/
|
|
103
|
+
static VALUE
|
|
104
|
+
rlbug_database_initialize( int argc, VALUE *argv, VALUE self )
|
|
105
|
+
{
|
|
106
|
+
rlbug_database *ptr = CHECK_DATABASE( self );
|
|
107
|
+
|
|
108
|
+
if ( !ptr ) {
|
|
109
|
+
VALUE path, options, config;
|
|
110
|
+
VALUE config_argv[1];
|
|
111
|
+
lbug_system_config *sysconfig;
|
|
112
|
+
char *database_path;
|
|
113
|
+
|
|
114
|
+
rb_scan_args( argc, argv, "1:", &path, &options );
|
|
115
|
+
if ( options == Qnil ) options = rb_hash_new();
|
|
116
|
+
config_argv[0] = options;
|
|
117
|
+
config = rb_funcallv_public_kw( rlbug_cLadybugConfig, rb_intern("from_options"), 1,
|
|
118
|
+
config_argv, RB_PASS_KEYWORDS );
|
|
119
|
+
|
|
120
|
+
sysconfig = rlbug_get_config( config );
|
|
121
|
+
database_path = StringValueCStr( path );
|
|
122
|
+
|
|
123
|
+
ptr = rlbug_database_alloc();
|
|
124
|
+
if ( lbug_database_init(database_path, *sysconfig, &ptr->db) != LbugSuccess ) {
|
|
125
|
+
xfree( ptr );
|
|
126
|
+
ptr = NULL;
|
|
127
|
+
|
|
128
|
+
rb_raise( rlbug_eDatabaseError, "Couldn't create database!" );
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
DEBUG_GC( ">>> allocated database %p\n", ptr );
|
|
132
|
+
RTYPEDDATA_DATA( self ) = ptr;
|
|
133
|
+
|
|
134
|
+
ptr->path = rb_obj_freeze( rb_obj_dup(path) );
|
|
135
|
+
ptr->config = rb_obj_freeze( config );
|
|
136
|
+
} else {
|
|
137
|
+
rb_raise( rb_eRuntimeError, "cannot reinit database" );
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
rb_call_super( 0, 0 );
|
|
141
|
+
|
|
142
|
+
return Qtrue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
/*
|
|
147
|
+
* call-seq:
|
|
148
|
+
* database.config() -> config
|
|
149
|
+
*
|
|
150
|
+
* Return the Ladybug::Config that reflects the config options the database
|
|
151
|
+
* was created with.
|
|
152
|
+
*
|
|
153
|
+
*/
|
|
154
|
+
static VALUE
|
|
155
|
+
rlbug_database_config( VALUE self )
|
|
156
|
+
{
|
|
157
|
+
rlbug_database *ptr = CHECK_DATABASE( self );
|
|
158
|
+
return ptr->config;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
/*
|
|
164
|
+
* call-seq:
|
|
165
|
+
* database.path() -> string or nil
|
|
166
|
+
*
|
|
167
|
+
* Return the path the database was created with, or +nil+ if it was
|
|
168
|
+
* created in memory.
|
|
169
|
+
*
|
|
170
|
+
*/
|
|
171
|
+
static VALUE
|
|
172
|
+
rlbug_database_path( VALUE self )
|
|
173
|
+
{
|
|
174
|
+
rlbug_database *ptr = CHECK_DATABASE( self );
|
|
175
|
+
|
|
176
|
+
if ( RSTRING_LEN(ptr->path) == 0 ) {
|
|
177
|
+
return Qnil;
|
|
178
|
+
} else {
|
|
179
|
+
return ptr->path;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
void
|
|
185
|
+
rlbug_init_database( void )
|
|
186
|
+
{
|
|
187
|
+
rlbug_cLadybugDatabase = rb_define_class_under( rlbug_mLadybug, "Database", rb_cObject );
|
|
188
|
+
|
|
189
|
+
rb_define_alloc_func( rlbug_cLadybugDatabase, rlbug_database_s_allocate );
|
|
190
|
+
|
|
191
|
+
rb_define_method( rlbug_cLadybugDatabase, "initialize", rlbug_database_initialize, -1 );
|
|
192
|
+
|
|
193
|
+
rb_define_method( rlbug_cLadybugDatabase, "config", rlbug_database_config, 0 );
|
|
194
|
+
rb_define_method( rlbug_cLadybugDatabase, "path", rlbug_database_path, 0 );
|
|
195
|
+
|
|
196
|
+
rb_require( "ladybug/database" );
|
|
197
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rbconfig'
|
|
4
|
+
require 'mkmf'
|
|
5
|
+
|
|
6
|
+
dir_config( 'ladybug' )
|
|
7
|
+
|
|
8
|
+
have_library( 'lbug' ) or
|
|
9
|
+
abort "No ladybug library!"
|
|
10
|
+
|
|
11
|
+
have_header( 'lbug.h' ) or
|
|
12
|
+
abort "No lbug.h header!"
|
|
13
|
+
have_header( 'ruby/thread.h' ) or
|
|
14
|
+
abort "Your Ruby is too old!"
|
|
15
|
+
|
|
16
|
+
have_func( 'lbug_database_init', 'lbug.h' )
|
|
17
|
+
|
|
18
|
+
create_header()
|
|
19
|
+
create_makefile( 'ladybug_ext' )
|
|
20
|
+
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ladybug_ext.c - Ruby binding for LadybugDB.
|
|
3
|
+
*
|
|
4
|
+
* Authors:
|
|
5
|
+
* * Michael Granger <ged@FaerieMUD.org>
|
|
6
|
+
*
|
|
7
|
+
* Refs:
|
|
8
|
+
* - https://docs.ladybugdb.com
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include "ladybug_ext.h"
|
|
13
|
+
|
|
14
|
+
VALUE rlbug_mLadybug;
|
|
15
|
+
|
|
16
|
+
VALUE rlbug_eError;
|
|
17
|
+
VALUE rlbug_eDatabaseError;
|
|
18
|
+
VALUE rlbug_eConnectionError;
|
|
19
|
+
VALUE rlbug_eQueryError;
|
|
20
|
+
VALUE rlbug_eFinishedError;
|
|
21
|
+
|
|
22
|
+
VALUE rlbug_rb_cDate;
|
|
23
|
+
VALUE rlbug_rb_cOstruct;
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/* --------------------------------------------------------------
|
|
27
|
+
* Logging Functions
|
|
28
|
+
* -------------------------------------------------------------- */
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* Log a message to the given +context+ object's logger.
|
|
32
|
+
*/
|
|
33
|
+
void
|
|
34
|
+
#if HAVE_STDARG_PROTOTYPES
|
|
35
|
+
rlbug_log_obj( VALUE context, const char *level, const char *fmt, ... )
|
|
36
|
+
#else
|
|
37
|
+
rlbug_log_obj( VALUE context, const char *level, const char *fmt, va_dcl )
|
|
38
|
+
#endif
|
|
39
|
+
{
|
|
40
|
+
char buf[BUFSIZ];
|
|
41
|
+
va_list args;
|
|
42
|
+
VALUE logger = Qnil;
|
|
43
|
+
VALUE message = Qnil;
|
|
44
|
+
|
|
45
|
+
va_init_list( args, fmt );
|
|
46
|
+
vsnprintf( buf, BUFSIZ, fmt, args );
|
|
47
|
+
message = rb_str_new2( buf );
|
|
48
|
+
|
|
49
|
+
logger = rb_funcall( context, rb_intern("log"), 0 );
|
|
50
|
+
rb_funcall( logger, rb_intern(level), 1, message );
|
|
51
|
+
|
|
52
|
+
va_end( args );
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
/*
|
|
57
|
+
* Log a message to the global logger.
|
|
58
|
+
*/
|
|
59
|
+
void
|
|
60
|
+
#if HAVE_STDARG_PROTOTYPES
|
|
61
|
+
rlbug_log( const char *level, const char *fmt, ... )
|
|
62
|
+
#else
|
|
63
|
+
rlbug_log( const char *level, const char *fmt, va_dcl )
|
|
64
|
+
#endif
|
|
65
|
+
{
|
|
66
|
+
char buf[BUFSIZ];
|
|
67
|
+
va_list args;
|
|
68
|
+
VALUE logger = Qnil;
|
|
69
|
+
VALUE message = Qnil;
|
|
70
|
+
|
|
71
|
+
va_init_list( args, fmt );
|
|
72
|
+
vsnprintf( buf, BUFSIZ, fmt, args );
|
|
73
|
+
message = rb_str_new2( buf );
|
|
74
|
+
|
|
75
|
+
logger = rb_funcall( rlbug_mLadybug, rb_intern("logger"), 0 );
|
|
76
|
+
rb_funcall( logger, rb_intern(level), 1, message );
|
|
77
|
+
|
|
78
|
+
va_end( args );
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/* --------------------------------------------------------------
|
|
84
|
+
* Module methods
|
|
85
|
+
* -------------------------------------------------------------- */
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
* call-seq:
|
|
89
|
+
* Ladybug.ladybug_version -> string
|
|
90
|
+
*
|
|
91
|
+
* Return the version of the underlying LadybugDB library.
|
|
92
|
+
*
|
|
93
|
+
*/
|
|
94
|
+
static VALUE
|
|
95
|
+
rlbug_s_ladybug_version( VALUE _ )
|
|
96
|
+
{
|
|
97
|
+
const char *version = lbug_get_version();
|
|
98
|
+
|
|
99
|
+
return rb_str_new2( version );
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
/*
|
|
104
|
+
* call-seq:
|
|
105
|
+
* Ladybug.storage_version -> integer
|
|
106
|
+
*
|
|
107
|
+
* Return the storage version used by the underlying library.
|
|
108
|
+
*
|
|
109
|
+
*/
|
|
110
|
+
static VALUE
|
|
111
|
+
rlbug_s_storage_version( VALUE _ )
|
|
112
|
+
{
|
|
113
|
+
const unsigned long long version = lbug_get_storage_version();
|
|
114
|
+
|
|
115
|
+
return ULONG2NUM( version );
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/*
|
|
120
|
+
* ladybug extension init function
|
|
121
|
+
*/
|
|
122
|
+
void
|
|
123
|
+
Init_ladybug_ext( void )
|
|
124
|
+
{
|
|
125
|
+
rb_require( "date" );
|
|
126
|
+
rlbug_rb_cDate = rb_const_get( rb_cObject, rb_intern("Date") );
|
|
127
|
+
|
|
128
|
+
rb_require( "ostruct" );
|
|
129
|
+
rlbug_rb_cOstruct = rb_const_get( rb_cObject, rb_intern("OpenStruct") );
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
* Document-module: Ladybug
|
|
133
|
+
*
|
|
134
|
+
* The top level namespace for Ladybug classes.
|
|
135
|
+
*/
|
|
136
|
+
rlbug_mLadybug = rb_define_module( "Ladybug" );
|
|
137
|
+
|
|
138
|
+
rb_define_singleton_method( rlbug_mLadybug, "ladybug_version", rlbug_s_ladybug_version, 0 );
|
|
139
|
+
rb_define_singleton_method( rlbug_mLadybug, "storage_version", rlbug_s_storage_version, 0 );
|
|
140
|
+
|
|
141
|
+
rlbug_eError = rb_define_class_under( rlbug_mLadybug, "Error", rb_eRuntimeError );
|
|
142
|
+
rlbug_eDatabaseError = rb_define_class_under( rlbug_mLadybug, "DatabaseError", rlbug_eError );
|
|
143
|
+
rlbug_eConnectionError = rb_define_class_under( rlbug_mLadybug, "ConnectionError", rlbug_eError );
|
|
144
|
+
rlbug_eQueryError = rb_define_class_under( rlbug_mLadybug, "QueryError", rlbug_eError );
|
|
145
|
+
rlbug_eFinishedError = rb_define_class_under( rlbug_mLadybug, "FinishedError", rlbug_eError );
|
|
146
|
+
|
|
147
|
+
rb_require( "ladybug" );
|
|
148
|
+
|
|
149
|
+
rlbug_init_database();
|
|
150
|
+
rlbug_init_config();
|
|
151
|
+
rlbug_init_connection();
|
|
152
|
+
rlbug_init_prepared_statement();
|
|
153
|
+
rlbug_init_result();
|
|
154
|
+
rlbug_init_query_summary();
|
|
155
|
+
rlbug_init_node();
|
|
156
|
+
rlbug_init_rel();
|
|
157
|
+
rlbug_init_recursive_rel();
|
|
158
|
+
}
|