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,132 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ladybug_ext.h - Ruby binding for LadybugDB
|
|
3
|
+
*
|
|
4
|
+
* Authors:
|
|
5
|
+
* * Michael Granger <ged@FaerieMUD.org>
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#ifndef LBUG_EXT_H_AA9CC4A5
|
|
10
|
+
#define LBUG_EXT_H_AA9CC4A5
|
|
11
|
+
|
|
12
|
+
#include "extconf.h"
|
|
13
|
+
|
|
14
|
+
#include <ruby.h>
|
|
15
|
+
#include <ruby/encoding.h>
|
|
16
|
+
#include <ruby/intern.h>
|
|
17
|
+
#include <ruby/thread.h>
|
|
18
|
+
#include <ruby/version.h>
|
|
19
|
+
|
|
20
|
+
#include <stdbool.h>
|
|
21
|
+
|
|
22
|
+
#include "lbug.h"
|
|
23
|
+
|
|
24
|
+
/* --------------------------------------------------------------
|
|
25
|
+
* Declarations
|
|
26
|
+
* -------------------------------------------------------------- */
|
|
27
|
+
|
|
28
|
+
#ifdef HAVE_STDARG_PROTOTYPES
|
|
29
|
+
#include <stdarg.h>
|
|
30
|
+
#define va_init_list(a, b) va_start (a, b)
|
|
31
|
+
void rlbug_log_obj (VALUE, const char *, const char *, ...)
|
|
32
|
+
__attribute__ ((format (printf, 2, 0)));
|
|
33
|
+
void rlbug_log (const char *, const char *, ...)
|
|
34
|
+
__attribute__ ((format (printf, 1, 0)));
|
|
35
|
+
#else
|
|
36
|
+
#include <varargs.h>
|
|
37
|
+
#define va_init_list(a, b) va_start (a)
|
|
38
|
+
void rlbug_log_obj (VALUE, const char *, const char *, va_dcl);
|
|
39
|
+
void rlbug_log (const char *, const char *, va_dcl);
|
|
40
|
+
#endif
|
|
41
|
+
|
|
42
|
+
/* --------------------------------------------------------------
|
|
43
|
+
* Structs
|
|
44
|
+
* -------------------------------------------------------------- */
|
|
45
|
+
|
|
46
|
+
typedef struct {
|
|
47
|
+
lbug_database db;
|
|
48
|
+
VALUE path;
|
|
49
|
+
VALUE config;
|
|
50
|
+
} rlbug_database;
|
|
51
|
+
|
|
52
|
+
typedef struct {
|
|
53
|
+
lbug_connection conn;
|
|
54
|
+
VALUE database;
|
|
55
|
+
VALUE queries;
|
|
56
|
+
VALUE statements;
|
|
57
|
+
} rlbug_connection;
|
|
58
|
+
|
|
59
|
+
typedef struct {
|
|
60
|
+
lbug_query_result result;
|
|
61
|
+
VALUE connection;
|
|
62
|
+
VALUE query;
|
|
63
|
+
VALUE statement;
|
|
64
|
+
VALUE previous_result;
|
|
65
|
+
VALUE next_result;
|
|
66
|
+
bool finished;
|
|
67
|
+
} rlbug_query_result;
|
|
68
|
+
|
|
69
|
+
typedef struct {
|
|
70
|
+
lbug_prepared_statement statement;
|
|
71
|
+
VALUE connection;
|
|
72
|
+
VALUE query;
|
|
73
|
+
bool finished;
|
|
74
|
+
} rlbug_prepared_statement;
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/* -------------------------------------------------------
|
|
78
|
+
* Globals
|
|
79
|
+
* ------------------------------------------------------- */
|
|
80
|
+
|
|
81
|
+
// Modules and classes
|
|
82
|
+
extern VALUE rlbug_mLadybug;
|
|
83
|
+
extern VALUE rlbug_cLadybugDatabase;
|
|
84
|
+
extern VALUE rlbug_cLadybugConfig;
|
|
85
|
+
extern VALUE rlbug_cLadybugConnection;
|
|
86
|
+
extern VALUE rlbug_cLadybugPreparedStatement;
|
|
87
|
+
extern VALUE rlbug_cLadybugResult;
|
|
88
|
+
extern VALUE rlbug_cLadybugQuerySummary;
|
|
89
|
+
extern VALUE rlbug_cLadybugNode;
|
|
90
|
+
extern VALUE rlbug_cLadybugRecursiveRel;
|
|
91
|
+
extern VALUE rlbug_cLadybugRel;
|
|
92
|
+
|
|
93
|
+
// Exception types
|
|
94
|
+
extern VALUE rlbug_eError;
|
|
95
|
+
extern VALUE rlbug_eDatabaseError;
|
|
96
|
+
extern VALUE rlbug_eConnectionError;
|
|
97
|
+
extern VALUE rlbug_eQueryError;
|
|
98
|
+
extern VALUE rlbug_eFinishedError;
|
|
99
|
+
|
|
100
|
+
// Internal refs to external classes
|
|
101
|
+
extern VALUE rlbug_rb_cDate;
|
|
102
|
+
extern VALUE rlbug_rb_cOstruct;
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
/* -------------------------------------------------------
|
|
106
|
+
* Initializer functions
|
|
107
|
+
* ------------------------------------------------------- */
|
|
108
|
+
extern void Init_ladybug_ext _ ((void));
|
|
109
|
+
|
|
110
|
+
extern void rlbug_init_database _ ((void));
|
|
111
|
+
extern void rlbug_init_config _ ((void));
|
|
112
|
+
extern void rlbug_init_connection _ ((void));
|
|
113
|
+
extern void rlbug_init_prepared_statement _ ((void));
|
|
114
|
+
extern void rlbug_init_result _ ((void));
|
|
115
|
+
extern void rlbug_init_query_summary _ ((void));
|
|
116
|
+
extern void rlbug_init_node _ ((void));
|
|
117
|
+
extern void rlbug_init_rel _ ((void));
|
|
118
|
+
extern void rlbug_init_recursive_rel _ ((void));
|
|
119
|
+
|
|
120
|
+
extern rlbug_database *rlbug_get_database _ ((VALUE));
|
|
121
|
+
extern lbug_system_config *rlbug_get_config _ ((VALUE));
|
|
122
|
+
extern rlbug_connection *rlbug_get_connection _ ((VALUE));
|
|
123
|
+
extern rlbug_prepared_statement *rlbug_get_prepared_statement _ ((VALUE));
|
|
124
|
+
extern rlbug_query_result *rlbug_get_result _ ((VALUE));
|
|
125
|
+
|
|
126
|
+
extern VALUE rlbug_convert_lbug_value_to_ruby _ ((lbug_data_type_id, lbug_value *));
|
|
127
|
+
extern VALUE rlbug_convert_logical_lbug_value_to_ruby _ ((lbug_logical_type *, lbug_value *));
|
|
128
|
+
extern VALUE rlbug_value_to_ruby _ (( lbug_value * ));
|
|
129
|
+
extern VALUE rlbug_result_from_query _ ((VALUE, VALUE, VALUE, lbug_query_result));
|
|
130
|
+
extern VALUE rlbug_result_from_prepared_statement _ ((VALUE, VALUE, VALUE, lbug_query_result));
|
|
131
|
+
|
|
132
|
+
#endif /* end of include guard: LBUG_EXT_H_AA9CC4A5 */
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* node.c - Ladybug::Node class
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "ladybug_ext.h"
|
|
7
|
+
|
|
8
|
+
VALUE rlbug_cLadybugNode;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Document-class: Ladybug::Node
|
|
13
|
+
*/
|
|
14
|
+
void
|
|
15
|
+
rlbug_init_node( void )
|
|
16
|
+
{
|
|
17
|
+
#ifdef FOR_RDOC
|
|
18
|
+
rlbug_mLadybug = rb_define_module( "ladybug" );
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
rlbug_cLadybugNode = rb_define_class_under( rlbug_mLadybug, "Node", rb_cObject );
|
|
22
|
+
|
|
23
|
+
rb_require( "ladybug/node" );
|
|
24
|
+
}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* prepared_statement.c - Ladybug::PreparedStatement class
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "lbug.h"
|
|
7
|
+
#include "ladybug_ext.h"
|
|
8
|
+
|
|
9
|
+
#define CHECK_PREPARED_STATEMENT( self ) \
|
|
10
|
+
((rlbug_prepared_statement *)rb_check_typeddata( (self), &rlbug_prepared_statement_type) )
|
|
11
|
+
// #define DEBUG_GC(msg, ptr) fprintf( stderr, msg, ptr )
|
|
12
|
+
#define DEBUG_GC(msg, ptr)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
VALUE rlbug_cLadybugPreparedStatement;
|
|
16
|
+
|
|
17
|
+
static void rlbug_prepared_statement_free( void * );
|
|
18
|
+
static void rlbug_prepared_statement_mark( void * );
|
|
19
|
+
static void rlbug_bind_string( rlbug_prepared_statement *, const char *, VALUE );
|
|
20
|
+
|
|
21
|
+
static const rb_data_type_t rlbug_prepared_statement_type = {
|
|
22
|
+
.wrap_struct_name = "Ladybug::PreparedStatement",
|
|
23
|
+
.function = {
|
|
24
|
+
.dfree = rlbug_prepared_statement_free,
|
|
25
|
+
.dmark = rlbug_prepared_statement_mark,
|
|
26
|
+
},
|
|
27
|
+
.data = NULL,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Fetch function
|
|
34
|
+
*/
|
|
35
|
+
rlbug_prepared_statement *
|
|
36
|
+
rlbug_get_prepared_statement( VALUE prepared_statement_obj )
|
|
37
|
+
{
|
|
38
|
+
return CHECK_PREPARED_STATEMENT( prepared_statement_obj );
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* Allocation function
|
|
44
|
+
*/
|
|
45
|
+
static rlbug_prepared_statement *
|
|
46
|
+
rlbug_prepared_statement_alloc( void )
|
|
47
|
+
{
|
|
48
|
+
rlbug_prepared_statement *ptr = ALLOC( rlbug_prepared_statement );
|
|
49
|
+
|
|
50
|
+
ptr->connection = Qnil;
|
|
51
|
+
ptr->query = Qnil;
|
|
52
|
+
|
|
53
|
+
return ptr;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* dmark function
|
|
59
|
+
*/
|
|
60
|
+
static void
|
|
61
|
+
rlbug_prepared_statement_mark( void *ptr )
|
|
62
|
+
{
|
|
63
|
+
rlbug_prepared_statement *prepared_statement_s = (rlbug_prepared_statement *)ptr;
|
|
64
|
+
|
|
65
|
+
if ( ptr ) {
|
|
66
|
+
rb_gc_mark( prepared_statement_s->connection );
|
|
67
|
+
rb_gc_mark( prepared_statement_s->query );
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* dfree function
|
|
74
|
+
*/
|
|
75
|
+
static void
|
|
76
|
+
rlbug_prepared_statement_free( void *ptr )
|
|
77
|
+
{
|
|
78
|
+
if ( ptr ) {
|
|
79
|
+
DEBUG_GC( ">>> freeing prepared statement %p\n", ptr );
|
|
80
|
+
// Can't lbug_prepared_statement_destroy here because the database or connection
|
|
81
|
+
// might already have been destroyed.
|
|
82
|
+
xfree( ptr );
|
|
83
|
+
ptr = NULL;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/*
|
|
89
|
+
* ::allocate function
|
|
90
|
+
*/
|
|
91
|
+
static VALUE
|
|
92
|
+
rlbug_prepared_statement_s_allocate( VALUE klass )
|
|
93
|
+
{
|
|
94
|
+
return TypedData_Wrap_Struct( klass, &rlbug_prepared_statement_type, NULL );
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
static VALUE
|
|
99
|
+
rlbug_prepared_statement_initialize( VALUE self, VALUE connection, VALUE query )
|
|
100
|
+
{
|
|
101
|
+
rlbug_prepared_statement *stmt = CHECK_PREPARED_STATEMENT( self );
|
|
102
|
+
|
|
103
|
+
if ( !stmt ) {
|
|
104
|
+
rlbug_connection *conn = rlbug_get_connection( connection );
|
|
105
|
+
const char *query_s = StringValueCStr( query );
|
|
106
|
+
|
|
107
|
+
stmt = rlbug_prepared_statement_alloc();
|
|
108
|
+
|
|
109
|
+
if ( lbug_connection_prepare(&conn->conn, query_s, &stmt->statement) != LbugSuccess ) {
|
|
110
|
+
char *err_detail = lbug_prepared_statement_get_error_message( &stmt->statement );
|
|
111
|
+
char errmsg[ 4096 ] = "\0";
|
|
112
|
+
|
|
113
|
+
snprintf( errmsg, 4096, "Could not prepare query `%s': %s.", query_s, err_detail );
|
|
114
|
+
|
|
115
|
+
xfree( stmt );
|
|
116
|
+
stmt = NULL;
|
|
117
|
+
lbug_destroy_string( err_detail );
|
|
118
|
+
|
|
119
|
+
rb_raise( rlbug_eQueryError, "%s", errmsg );
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
DEBUG_GC( ">>> allocated prepared statement %p\n", stmt );
|
|
123
|
+
RTYPEDDATA_DATA( self ) = stmt;
|
|
124
|
+
|
|
125
|
+
stmt->connection = connection;
|
|
126
|
+
stmt->query = query;
|
|
127
|
+
|
|
128
|
+
} else {
|
|
129
|
+
rb_raise( rb_eRuntimeError, "cannot reinit prepared statement" );
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
rb_call_super( 0, 0 );
|
|
133
|
+
|
|
134
|
+
return Qtrue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
struct execute_call {
|
|
139
|
+
lbug_connection *conn;
|
|
140
|
+
lbug_prepared_statement *stmt;
|
|
141
|
+
lbug_query_result *result;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
static void *
|
|
146
|
+
rlbug_connection_do_execute_without_gvl( void *ptr )
|
|
147
|
+
{
|
|
148
|
+
struct execute_call *qcall = (struct execute_call *)ptr;
|
|
149
|
+
lbug_state state;
|
|
150
|
+
|
|
151
|
+
state = lbug_connection_execute( qcall->conn, qcall->stmt, qcall->result );
|
|
152
|
+
|
|
153
|
+
return (void *)state;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
static void
|
|
158
|
+
rlbug_connection_cancel_execute( void *ptr )
|
|
159
|
+
{
|
|
160
|
+
lbug_connection *conn = (lbug_connection *)ptr;
|
|
161
|
+
lbug_connection_interrupt( conn );
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
// Inner prepared statement constructor
|
|
166
|
+
static lbug_query_result
|
|
167
|
+
rlbug_prepared_statement_do_execute( VALUE self )
|
|
168
|
+
{
|
|
169
|
+
rlbug_prepared_statement *stmt = CHECK_PREPARED_STATEMENT( self );
|
|
170
|
+
VALUE connection = stmt->connection;
|
|
171
|
+
rlbug_connection *conn = rlbug_get_connection( connection );
|
|
172
|
+
lbug_query_result result;
|
|
173
|
+
struct execute_call qcall;
|
|
174
|
+
lbug_state execute_state;
|
|
175
|
+
void *result_ptr;
|
|
176
|
+
|
|
177
|
+
qcall.conn = &conn->conn;
|
|
178
|
+
qcall.stmt = &stmt->statement;
|
|
179
|
+
qcall.result = &result;
|
|
180
|
+
|
|
181
|
+
result_ptr = rb_thread_call_without_gvl(
|
|
182
|
+
rlbug_connection_do_execute_without_gvl, (void *)&qcall,
|
|
183
|
+
rlbug_connection_cancel_execute, (void *)&conn->conn );
|
|
184
|
+
|
|
185
|
+
_Pragma("GCC diagnostic push")
|
|
186
|
+
_Pragma("GCC diagnostic ignored \"-Wvoid-pointer-to-enum-cast\"")
|
|
187
|
+
execute_state = (lbug_state)result_ptr;
|
|
188
|
+
_Pragma("GCC diagnostic pop")
|
|
189
|
+
|
|
190
|
+
if ( execute_state != LbugSuccess ) {
|
|
191
|
+
char *err_detail = lbug_query_result_get_error_message( &result );
|
|
192
|
+
char errmsg[ 4096 ] = "\0";
|
|
193
|
+
|
|
194
|
+
snprintf( errmsg, 4096, "Could not execute prepared statement: %s.", err_detail );
|
|
195
|
+
|
|
196
|
+
lbug_destroy_string( err_detail );
|
|
197
|
+
lbug_query_result_destroy( &result );
|
|
198
|
+
|
|
199
|
+
rb_raise( rlbug_eQueryError, "%s", errmsg );
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return *qcall.result;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
static VALUE
|
|
207
|
+
rlbug_prepared_statement__execute( VALUE self )
|
|
208
|
+
{
|
|
209
|
+
rlbug_prepared_statement *stmt = CHECK_PREPARED_STATEMENT( self );
|
|
210
|
+
lbug_query_result result = rlbug_prepared_statement_do_execute( self );
|
|
211
|
+
|
|
212
|
+
return rlbug_result_from_prepared_statement( rlbug_cLadybugResult, stmt->connection, self, result );
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
static VALUE
|
|
217
|
+
rlbug_prepared_statement__execute_bang( VALUE self )
|
|
218
|
+
{
|
|
219
|
+
lbug_query_result result = rlbug_prepared_statement_do_execute( self );
|
|
220
|
+
return lbug_query_result_is_success( &result ) ? Qtrue : Qfalse;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
/*
|
|
225
|
+
* call-seq:
|
|
226
|
+
* statement.success? -> true or false
|
|
227
|
+
*
|
|
228
|
+
* Returns +true+ if the query was prepared successfully.
|
|
229
|
+
*
|
|
230
|
+
*/
|
|
231
|
+
static VALUE
|
|
232
|
+
rlbug_prepared_statement_success_p( VALUE self )
|
|
233
|
+
{
|
|
234
|
+
rlbug_prepared_statement *stmt = CHECK_PREPARED_STATEMENT( self );
|
|
235
|
+
|
|
236
|
+
if ( lbug_prepared_statement_is_success(&stmt->statement) ) {
|
|
237
|
+
return Qtrue;
|
|
238
|
+
} else {
|
|
239
|
+
return Qfalse;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
/*
|
|
245
|
+
* call-seq:
|
|
246
|
+
* statement.bind_variable( name, value )
|
|
247
|
+
*
|
|
248
|
+
* Binds the given +value+ to the given parameter +name+ in the prepared statement
|
|
249
|
+
*
|
|
250
|
+
*/
|
|
251
|
+
static VALUE
|
|
252
|
+
rlbug_prepared_statement_bind_variable( VALUE self, VALUE name, VALUE value )
|
|
253
|
+
{
|
|
254
|
+
rlbug_prepared_statement *stmt = CHECK_PREPARED_STATEMENT( self );
|
|
255
|
+
VALUE name_string = rb_funcall( name, rb_intern("to_s"), 0 );
|
|
256
|
+
const char *name_s = StringValueCStr( name_string );
|
|
257
|
+
lbug_value *null_value;
|
|
258
|
+
|
|
259
|
+
switch (TYPE(value)) {
|
|
260
|
+
case T_TRUE:
|
|
261
|
+
case T_FALSE:
|
|
262
|
+
lbug_prepared_statement_bind_bool( &stmt->statement, name_s, RTEST(value) );
|
|
263
|
+
break;
|
|
264
|
+
|
|
265
|
+
// fallthrough
|
|
266
|
+
case T_FLOAT:
|
|
267
|
+
lbug_prepared_statement_bind_float( &stmt->statement, name_s, NUM2DBL(value) );
|
|
268
|
+
break;
|
|
269
|
+
|
|
270
|
+
case T_BIGNUM:
|
|
271
|
+
lbug_prepared_statement_bind_int64( &stmt->statement, name_s, NUM2LL(value) );
|
|
272
|
+
break;
|
|
273
|
+
|
|
274
|
+
case T_FIXNUM:
|
|
275
|
+
lbug_prepared_statement_bind_int32( &stmt->statement, name_s, NUM2INT(value) );
|
|
276
|
+
break;
|
|
277
|
+
|
|
278
|
+
case T_SYMBOL:
|
|
279
|
+
rb_notimplement();
|
|
280
|
+
break; // not reached
|
|
281
|
+
|
|
282
|
+
case T_NIL:
|
|
283
|
+
null_value = lbug_value_create_null();
|
|
284
|
+
lbug_prepared_statement_bind_value( &stmt->statement, name_s, null_value );
|
|
285
|
+
lbug_value_destroy( null_value );
|
|
286
|
+
break;
|
|
287
|
+
|
|
288
|
+
case T_OBJECT:
|
|
289
|
+
case T_CLASS:
|
|
290
|
+
case T_MODULE:
|
|
291
|
+
case T_REGEXP:
|
|
292
|
+
case T_ARRAY:
|
|
293
|
+
case T_HASH:
|
|
294
|
+
case T_STRUCT:
|
|
295
|
+
case T_COMPLEX:
|
|
296
|
+
case T_RATIONAL:
|
|
297
|
+
case T_FILE:
|
|
298
|
+
case T_DATA:
|
|
299
|
+
case T_STRING:
|
|
300
|
+
default:
|
|
301
|
+
rlbug_bind_string( stmt, name_s, value );
|
|
302
|
+
break;
|
|
303
|
+
|
|
304
|
+
// lbug_prepared_statement_bind_int8
|
|
305
|
+
// lbug_prepared_statement_bind_int16
|
|
306
|
+
// lbug_prepared_statement_bind_uint64
|
|
307
|
+
// lbug_prepared_statement_bind_uint32
|
|
308
|
+
// lbug_prepared_statement_bind_uint16
|
|
309
|
+
// lbug_prepared_statement_bind_uint8
|
|
310
|
+
|
|
311
|
+
// lbug_prepared_statement_bind_double
|
|
312
|
+
// lbug_prepared_statement_bind_date
|
|
313
|
+
// lbug_prepared_statement_bind_timestamp_ns
|
|
314
|
+
// lbug_prepared_statement_bind_timestamp_sec
|
|
315
|
+
// lbug_prepared_statement_bind_timestamp_tz
|
|
316
|
+
// lbug_prepared_statement_bind_timestamp_ms
|
|
317
|
+
// lbug_prepared_statement_bind_timestamp
|
|
318
|
+
// lbug_prepared_statement_bind_interval
|
|
319
|
+
// lbug_prepared_statement_bind_value
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return Qtrue;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
static void
|
|
327
|
+
rlbug_bind_string( rlbug_prepared_statement *stmt, const char *name_s, VALUE value )
|
|
328
|
+
{
|
|
329
|
+
const char *value_s = StringValueCStr( value );
|
|
330
|
+
lbug_prepared_statement_bind_string( &stmt->statement, name_s, value_s );
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
/*
|
|
335
|
+
* call-seq:
|
|
336
|
+
* statement.connection -> conn
|
|
337
|
+
*
|
|
338
|
+
* Return the Ladybug::Connection used to run this statement.
|
|
339
|
+
*
|
|
340
|
+
*/
|
|
341
|
+
static VALUE
|
|
342
|
+
rlbug_prepared_statement_connection( VALUE self )
|
|
343
|
+
{
|
|
344
|
+
rlbug_prepared_statement *statement_s = rlbug_get_prepared_statement( self );
|
|
345
|
+
return statement_s->connection;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
/*
|
|
350
|
+
* call-seq:
|
|
351
|
+
* statement.query -> string
|
|
352
|
+
*
|
|
353
|
+
* Return the query string used to build this statement.
|
|
354
|
+
*
|
|
355
|
+
*/
|
|
356
|
+
static VALUE
|
|
357
|
+
rlbug_prepared_statement_query( VALUE self )
|
|
358
|
+
{
|
|
359
|
+
rlbug_prepared_statement *statement_s = rlbug_get_prepared_statement( self );
|
|
360
|
+
return statement_s->query;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
/*
|
|
366
|
+
* Document-class: Ladybug::PreparedStatement
|
|
367
|
+
*/
|
|
368
|
+
void
|
|
369
|
+
rlbug_init_prepared_statement( void )
|
|
370
|
+
{
|
|
371
|
+
#ifdef FOR_RDOC
|
|
372
|
+
rlbug_mLadybug = rb_define_module( "ladybug" );
|
|
373
|
+
#endif
|
|
374
|
+
|
|
375
|
+
rlbug_cLadybugPreparedStatement = rb_define_class_under( rlbug_mLadybug, "PreparedStatement", rb_cObject );
|
|
376
|
+
|
|
377
|
+
rb_define_alloc_func( rlbug_cLadybugPreparedStatement, rlbug_prepared_statement_s_allocate );
|
|
378
|
+
|
|
379
|
+
rb_define_protected_method( rlbug_cLadybugPreparedStatement, "initialize",
|
|
380
|
+
rlbug_prepared_statement_initialize, 2 );
|
|
381
|
+
rb_define_protected_method( rlbug_cLadybugPreparedStatement, "_execute",
|
|
382
|
+
rlbug_prepared_statement__execute, 0 );
|
|
383
|
+
rb_define_protected_method( rlbug_cLadybugPreparedStatement, "_execute!",
|
|
384
|
+
rlbug_prepared_statement__execute_bang, 0 );
|
|
385
|
+
|
|
386
|
+
rb_define_method( rlbug_cLadybugPreparedStatement, "connection",
|
|
387
|
+
rlbug_prepared_statement_connection, 0 );
|
|
388
|
+
rb_define_method( rlbug_cLadybugPreparedStatement, "query",
|
|
389
|
+
rlbug_prepared_statement_query, 0 );
|
|
390
|
+
|
|
391
|
+
rb_define_method( rlbug_cLadybugPreparedStatement, "success?", rlbug_prepared_statement_success_p, 0 );
|
|
392
|
+
rb_define_method( rlbug_cLadybugPreparedStatement, "bind_variable",
|
|
393
|
+
rlbug_prepared_statement_bind_variable, 2 );
|
|
394
|
+
|
|
395
|
+
rb_require( "ladybug/prepared_statement" );
|
|
396
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* query_summary.c - Ladybug::QuerySummary class
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "ladybug_ext.h"
|
|
7
|
+
|
|
8
|
+
#define CHECK_QUERY_SUMMARY(self) \
|
|
9
|
+
((lbug_query_summary*)rb_check_typeddata((self), &rlbug_query_summary_type))
|
|
10
|
+
// #define DEBUG_GC(msg, ptr) fprintf( stderr, msg, ptr )
|
|
11
|
+
#define DEBUG_GC(msg, ptr)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
VALUE rlbug_cLadybugQuerySummary;
|
|
15
|
+
|
|
16
|
+
static void rlbug_query_summary_free( void * );
|
|
17
|
+
|
|
18
|
+
static const rb_data_type_t rlbug_query_summary_type = {
|
|
19
|
+
.wrap_struct_name = "Ladybug::QuerySummary",
|
|
20
|
+
.function = {
|
|
21
|
+
.dfree = rlbug_query_summary_free,
|
|
22
|
+
},
|
|
23
|
+
.data = NULL,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
static void
|
|
28
|
+
rlbug_query_summary_free( void *ptr )
|
|
29
|
+
{
|
|
30
|
+
lbug_query_summary *query_summary = (lbug_query_summary *)ptr;
|
|
31
|
+
|
|
32
|
+
if ( ptr ) {
|
|
33
|
+
DEBUG_GC( ">>> freeing query summary %p\n", ptr );
|
|
34
|
+
lbug_query_summary_destroy( query_summary );
|
|
35
|
+
xfree( ptr );
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
/*
|
|
41
|
+
* ::allocate function
|
|
42
|
+
*/
|
|
43
|
+
static VALUE
|
|
44
|
+
rlbug_query_summary_s_allocate( VALUE klass )
|
|
45
|
+
{
|
|
46
|
+
return TypedData_Wrap_Struct( klass, &rlbug_query_summary_type, NULL );
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/*
|
|
51
|
+
* call-seq:
|
|
52
|
+
* Ladybug::QuerySummary.from_result( result ) -> query_summary
|
|
53
|
+
*
|
|
54
|
+
* Return a Ladybug::QuerySummary from a Ladybug::Result.
|
|
55
|
+
*
|
|
56
|
+
*/
|
|
57
|
+
static VALUE
|
|
58
|
+
rlbug_query_summary_s_from_result( VALUE klass, VALUE query_result )
|
|
59
|
+
{
|
|
60
|
+
rlbug_query_result *result = rlbug_get_result( query_result );
|
|
61
|
+
|
|
62
|
+
lbug_query_summary *query_summary = ALLOC( lbug_query_summary );
|
|
63
|
+
VALUE query_summary_obj = rb_class_new_instance( 0, 0, klass );
|
|
64
|
+
|
|
65
|
+
/*
|
|
66
|
+
TODO Release the GIL
|
|
67
|
+
*/
|
|
68
|
+
if ( lbug_query_result_get_query_summary(&result->result, query_summary) != LbugSuccess ) {
|
|
69
|
+
xfree( query_summary );
|
|
70
|
+
query_summary = NULL;
|
|
71
|
+
rb_raise( rlbug_eQueryError, "Could not fetch the query summary." );
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
DEBUG_GC( ">>> allocated query summary %p\n", query_summary );
|
|
75
|
+
RTYPEDDATA_DATA( query_summary_obj ) = query_summary;
|
|
76
|
+
|
|
77
|
+
return query_summary_obj;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* call-seq:
|
|
83
|
+
* summary.compiling_time -> float
|
|
84
|
+
*
|
|
85
|
+
* Returns the compilation time of the given query summary in milliseconds.
|
|
86
|
+
*
|
|
87
|
+
*/
|
|
88
|
+
static VALUE
|
|
89
|
+
rlbug_query_summary_compiling_time( VALUE self )
|
|
90
|
+
{
|
|
91
|
+
lbug_query_summary *summary = CHECK_QUERY_SUMMARY( self );
|
|
92
|
+
double result = lbug_query_summary_get_compiling_time( summary );
|
|
93
|
+
|
|
94
|
+
return rb_float_new( result );
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* call-seq:
|
|
100
|
+
* summary.execution_time -> float
|
|
101
|
+
*
|
|
102
|
+
* Returns the execution time of the given query summary in milliseconds.
|
|
103
|
+
*
|
|
104
|
+
*/
|
|
105
|
+
static VALUE
|
|
106
|
+
rlbug_query_summary_execution_time( VALUE self )
|
|
107
|
+
{
|
|
108
|
+
lbug_query_summary *summary = CHECK_QUERY_SUMMARY( self );
|
|
109
|
+
double result = lbug_query_summary_get_execution_time( summary );
|
|
110
|
+
|
|
111
|
+
return rb_float_new( result );
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
* Document-class: Ladybug::QuerySummary
|
|
117
|
+
*/
|
|
118
|
+
void
|
|
119
|
+
rlbug_init_query_summary( void )
|
|
120
|
+
{
|
|
121
|
+
#ifdef FOR_RDOC
|
|
122
|
+
rlbug_mLadybug = rb_define_module( "ladybug" );
|
|
123
|
+
#endif
|
|
124
|
+
|
|
125
|
+
rlbug_cLadybugQuerySummary = rb_define_class_under( rlbug_mLadybug, "QuerySummary", rb_cObject );
|
|
126
|
+
|
|
127
|
+
rb_define_alloc_func( rlbug_cLadybugQuerySummary, rlbug_query_summary_s_allocate );
|
|
128
|
+
rb_undef_method( CLASS_OF(rlbug_cLadybugQuerySummary), "new" );
|
|
129
|
+
|
|
130
|
+
rb_define_singleton_method( rlbug_cLadybugQuerySummary, "from_result",
|
|
131
|
+
rlbug_query_summary_s_from_result, 1 );
|
|
132
|
+
rb_define_alias( CLASS_OF(rlbug_cLadybugQuerySummary), "from_query_result", "from_result" );
|
|
133
|
+
|
|
134
|
+
rb_define_method( rlbug_cLadybugQuerySummary, "compiling_time",
|
|
135
|
+
rlbug_query_summary_compiling_time, 0 );
|
|
136
|
+
rb_define_method( rlbug_cLadybugQuerySummary, "execution_time",
|
|
137
|
+
rlbug_query_summary_execution_time, 0 );
|
|
138
|
+
|
|
139
|
+
rb_require( "ladybug/query_summary" );
|
|
140
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* recursive_rel.c - Ladybug::RecursiveRel class
|
|
3
|
+
*
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "ladybug_ext.h"
|
|
7
|
+
|
|
8
|
+
VALUE rlbug_cLadybugRecursiveRel;
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Document-class: Ladybug::RecursiveRel
|
|
13
|
+
*/
|
|
14
|
+
void
|
|
15
|
+
rlbug_init_recursive_rel( void )
|
|
16
|
+
{
|
|
17
|
+
#ifdef FOR_RDOC
|
|
18
|
+
rlbug_mLadybug = rb_define_module( "ladybug" );
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
rlbug_cLadybugRecursiveRel = rb_define_class_under( rlbug_mLadybug, "RecursiveRel", rb_cObject );
|
|
22
|
+
|
|
23
|
+
rb_require( "ladybug/recursive_rel" );
|
|
24
|
+
}
|