amalgalite 0.1.0 → 0.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.
- data/HISTORY +18 -1
- data/README +12 -4
- data/ext/amalgalite3.c +1 -0
- data/ext/amalgalite3.h +25 -1
- data/ext/amalgalite3_blob.c +238 -0
- data/ext/amalgalite3_database.c +39 -0
- data/ext/amalgalite3_statement.c +85 -2
- data/gemspec.rb +1 -0
- data/lib/amalgalite.rb +1 -0
- data/lib/amalgalite/blob.rb +169 -4
- data/lib/amalgalite/column.rb +5 -2
- data/lib/amalgalite/schema.rb +5 -1
- data/lib/amalgalite/statement.rb +107 -20
- data/lib/amalgalite/table.rb +3 -1
- data/lib/amalgalite/taps.rb +2 -0
- data/lib/amalgalite/type_maps/default_map.rb +15 -1
- data/lib/amalgalite/version.rb +1 -1
- data/lib/amalgalite/view.rb +2 -0
- data/spec/blob_spec.rb +81 -0
- data/spec/default_map_spec.rb +3 -2
- data/spec/statement_spec.rb +18 -0
- data/spec/storage_map_spec.rb +1 -1
- metadata +17 -3
data/HISTORY
CHANGED
@@ -1,4 +1,21 @@
|
|
1
1
|
= Changelog
|
2
|
-
== Version 0.
|
2
|
+
== Version 0.2.0 - 2008-07-04
|
3
|
+
|
4
|
+
* Major Enhancements
|
5
|
+
* blob support, both incremental access and normal access
|
6
|
+
|
7
|
+
* Minor Enhancements
|
8
|
+
* added examples/gem_db.rb script demonstrating taps and prepared statements
|
9
|
+
* added examples/schema-info.rb script demonstrating meta information
|
10
|
+
* added examples/blob.rb demonstrating incremental blob IO
|
11
|
+
* added acces to the SQLite3 errcode and errmsg api
|
12
|
+
|
13
|
+
* Bugfixes
|
14
|
+
* added taps.rb for requiring
|
15
|
+
* fixed prepared statement reset
|
16
|
+
* caught an error in executing prepared statements earlier in the process so
|
17
|
+
the correct error is reported
|
18
|
+
|
19
|
+
== Version 0.1.0 - 2008-06-21
|
3
20
|
|
4
21
|
* Initial public release
|
data/README
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
== Amalgalite
|
2
2
|
|
3
|
-
* Homepage[http://
|
3
|
+
* Homepage[http://copiousfreetime.rubyforge.org/amalgalite]
|
4
4
|
* {Rubyforge Project}[http://rubyforge.org/projects/copiousfreetime/]
|
5
5
|
* email jeremy at copiousfreetime dot org
|
6
|
+
* git clone url git://github.com/copiousfreetime/amalgalite.git
|
6
7
|
|
7
8
|
== INSTALL
|
8
9
|
|
@@ -10,10 +11,17 @@
|
|
10
11
|
|
11
12
|
== DESCRIPTION
|
12
13
|
|
13
|
-
Amalgalite embeds the SQLite database engine in a ruby extension.
|
14
|
+
Amalgalite embeds the SQLite database engine in a ruby extension. There is no
|
15
|
+
need to install SQLite separately.
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
Look in the examples/ directory to see
|
18
|
+
|
19
|
+
* general usage
|
20
|
+
* blob io
|
21
|
+
* schema information
|
22
|
+
|
23
|
+
Also Scroll through Amalgalite::Database for a quick example, and a general
|
24
|
+
overview of the API.
|
17
25
|
|
18
26
|
== CREDITS
|
19
27
|
|
data/ext/amalgalite3.c
CHANGED
data/ext/amalgalite3.h
CHANGED
@@ -24,6 +24,14 @@ typedef struct am_sqlite3_stmt {
|
|
24
24
|
VALUE remaining_sql;
|
25
25
|
} am_sqlite3_stmt;
|
26
26
|
|
27
|
+
/* wrapper struct around the sqlite3_blob opaque ponter */
|
28
|
+
typedef struct am_sqlite3_blob {
|
29
|
+
sqlite3_blob *blob;
|
30
|
+
sqlite3 *db;
|
31
|
+
int length;
|
32
|
+
int current_offset;
|
33
|
+
} am_sqlite3_blob;
|
34
|
+
|
27
35
|
|
28
36
|
/** module and classes **/
|
29
37
|
extern VALUE mA; /* module Amalgalite */
|
@@ -55,7 +63,7 @@ extern VALUE am_sqlite3_database_register_profile_tap(VALUE self, VALUE tap);
|
|
55
63
|
/*----------------------------------------------------------------------
|
56
64
|
* Prototype for Amalgalite::SQLite3::Statement
|
57
65
|
*---------------------------------------------------------------------*/
|
58
|
-
extern VALUE cAS_Statement; /* class
|
66
|
+
extern VALUE cAS_Statement; /* class Amalgalite::SQLite3::Statement */
|
59
67
|
|
60
68
|
extern VALUE am_sqlite3_statement_alloc(VALUE klass);
|
61
69
|
extern void am_sqlite3_statement_free(am_sqlite3_stmt* );
|
@@ -66,6 +74,7 @@ extern VALUE am_sqlite3_statement_column_count(VALUE self);
|
|
66
74
|
extern VALUE am_sqlite3_statement_column_name(VALUE self, VALUE index);
|
67
75
|
extern VALUE am_sqlite3_statement_column_decltype(VALUE self, VALUE index);
|
68
76
|
extern VALUE am_sqlite3_statement_column_type(VALUE self, VALUE index);
|
77
|
+
extern VALUE am_sqlite3_statement_column_blob(VALUE self, VALUE index);
|
69
78
|
extern VALUE am_sqlite3_statement_column_text(VALUE self, VALUE index);
|
70
79
|
extern VALUE am_sqlite3_statement_column_int(VALUE self, VALUE index);
|
71
80
|
extern VALUE am_sqlite3_statement_column_int64(VALUE self, VALUE index);
|
@@ -81,11 +90,26 @@ extern VALUE am_sqlite3_statement_bind_parameter_count(VALUE self);
|
|
81
90
|
extern VALUE am_sqlite3_statement_bind_parameter_index(VALUE self, VALUE parameter_name);
|
82
91
|
extern VALUE am_sqlite3_statement_remaining_sql(VALUE self);
|
83
92
|
extern VALUE am_sqlite3_statement_bind_text(VALUE self, VALUE position, VALUE value);
|
93
|
+
extern VALUE am_sqlite3_statement_bind_blob(VALUE self, VALUE position, VALUE value);
|
94
|
+
extern VALUE am_sqlite3_statement_bind_zeroblob(VALUE self, VALUE position, VALUE value);
|
84
95
|
extern VALUE am_sqlite3_statement_bind_int(VALUE self, VALUE position, VALUE value);
|
85
96
|
extern VALUE am_sqlite3_statement_bind_int64(VALUE self, VALUE position, VALUE value);
|
86
97
|
extern VALUE am_sqlite3_statement_bind_double(VALUE self, VALUE position, VALUE value);
|
87
98
|
extern VALUE am_sqlite3_statement_bind_null(VALUE self, VALUE position);
|
88
99
|
|
100
|
+
/*----------------------------------------------------------------------
|
101
|
+
* Prototype for Amalgalite::SQLite3::Blob
|
102
|
+
*---------------------------------------------------------------------*/
|
103
|
+
extern VALUE cAS_Blob; /* class Amalgalite::SQLite3::Blob */
|
104
|
+
|
105
|
+
extern VALUE am_sqlite3_blob_alloc(VALUE klass);
|
106
|
+
extern VALUE am_sqlite3_blob_initialize( VALUE self, VALUE db, VALUE db_name, VALUE table_name, VALUE column_name, VALUE rowid, VALUE flag) ;
|
107
|
+
extern void am_sqlite3_blob_free(am_sqlite3_blob* );
|
108
|
+
extern VALUE am_sqlite3_blob_read(VALUE self, VALUE length);
|
109
|
+
extern VALUE am_sqlite3_blob_write(VALUE self, VALUE buffer);
|
110
|
+
extern VALUE am_sqlite3_blob_close(VALUE self);
|
111
|
+
extern VALUE am_sqlite3_blob_length(VALUE self);
|
112
|
+
|
89
113
|
/***********************************************************************
|
90
114
|
* Type conversion macros between sqlite data types and ruby types
|
91
115
|
**********************************************************************/
|
@@ -0,0 +1,238 @@
|
|
1
|
+
#include "amalgalite3.h"
|
2
|
+
/**
|
3
|
+
* Copyright (c) 2008 Jeremy Hinegardner
|
4
|
+
* All rights reserved. See LICENSE and/or COPYING for details.
|
5
|
+
*
|
6
|
+
* vim: shiftwidth=4
|
7
|
+
*/
|
8
|
+
|
9
|
+
VALUE cAS_Blob; /* class Amalgliate::SQLite3::Blob */
|
10
|
+
|
11
|
+
/**
|
12
|
+
* call-seq:
|
13
|
+
* Blob.new( database, table_name, column_name, row_id, flag ) -> Blob
|
14
|
+
*
|
15
|
+
* Create a new Blob object and associate it with the approriate, database,
|
16
|
+
* table, column and row. +flag+ indicates if the Blob is to be opened for
|
17
|
+
* writing "w" or reading "r".
|
18
|
+
*
|
19
|
+
*/
|
20
|
+
VALUE am_sqlite3_blob_initialize( VALUE self, VALUE db, VALUE db_name, VALUE table_name, VALUE column_name, VALUE rowid, VALUE flag)
|
21
|
+
{
|
22
|
+
am_sqlite3_blob *am_blob;
|
23
|
+
int rc;
|
24
|
+
am_sqlite3 *am_db;
|
25
|
+
char *zDb = StringValuePtr( db_name );
|
26
|
+
char *zTable = StringValuePtr( table_name );
|
27
|
+
char *zColumn = StringValuePtr( column_name );
|
28
|
+
sqlite3_int64 iRow = NUM2SQLINT64( rowid ) ;
|
29
|
+
VALUE flag_str = StringValue( flag );
|
30
|
+
int flags = 0;
|
31
|
+
|
32
|
+
/* extract the blob struct */
|
33
|
+
Data_Get_Struct(self, am_sqlite3_blob, am_blob);
|
34
|
+
|
35
|
+
/* extract the sqlite3 db struct */
|
36
|
+
Data_Get_Struct(db, am_sqlite3, am_db);
|
37
|
+
|
38
|
+
/* make sure that the flags are valid, only 'r' or 'w' are allowed */
|
39
|
+
if ( ( RSTRING( flag_str )->len != 1) ||
|
40
|
+
( ( 'r' != RSTRING( flag_str )->ptr[0] ) &&
|
41
|
+
( 'w' != RSTRING( flag_str )->ptr[0] ))) {
|
42
|
+
rb_raise( eAS_Error, "Error opening Blob in db = %s, table = %s, column = %s, rowid = %d. Invalid flag '%s'. Must be either 'w' or 'r'\n",
|
43
|
+
zDb, zTable, zColumn, iRow, RSTRING( flag_str )->ptr);
|
44
|
+
}
|
45
|
+
|
46
|
+
/* switch to write mode */
|
47
|
+
if ( 'w' == RSTRING( flag_str )->ptr[0] ) {
|
48
|
+
flags = 1;
|
49
|
+
}
|
50
|
+
|
51
|
+
/* open the blob and associate the db to it */
|
52
|
+
rc = sqlite3_blob_open(am_db->db, zDb, zTable, zColumn, iRow, flags, &(am_blob->blob) );
|
53
|
+
if ( rc != SQLITE_OK ) {
|
54
|
+
rb_raise( eAS_Error, "Error opening Blob in db = %s, table = %s, column = %s, rowid = %ld : [SQLITE_ERROR %d] %s\n",
|
55
|
+
zDb, zTable, zColumn, iRow, rc, sqlite3_errmsg( am_db->db ));
|
56
|
+
}
|
57
|
+
am_blob->length = sqlite3_blob_bytes( am_blob->blob );
|
58
|
+
am_blob->db = am_db->db;
|
59
|
+
|
60
|
+
/* if a block is given then yield self and close the blob when done */
|
61
|
+
if ( rb_block_given_p() ) {
|
62
|
+
rb_yield( self );
|
63
|
+
am_sqlite3_blob_close( self );
|
64
|
+
return Qnil;
|
65
|
+
} else {
|
66
|
+
return self;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* call-seq:
|
72
|
+
* blob.close -> nil
|
73
|
+
*
|
74
|
+
* Closes the blob.
|
75
|
+
*/
|
76
|
+
VALUE am_sqlite3_blob_close( VALUE self )
|
77
|
+
{
|
78
|
+
am_sqlite3_blob *am_blob;
|
79
|
+
int rc;
|
80
|
+
|
81
|
+
Data_Get_Struct(self, am_sqlite3_blob, am_blob);
|
82
|
+
rc = sqlite3_blob_close( am_blob->blob );
|
83
|
+
if ( SQLITE_OK != rc ) {
|
84
|
+
rb_raise(eAS_Error, "Error closing blob: [SQLITE_ERROR %d] %s\n",
|
85
|
+
rc, sqlite3_errmsg( am_blob->db ));
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
return Qnil;
|
90
|
+
}
|
91
|
+
|
92
|
+
|
93
|
+
/**
|
94
|
+
* call-seq:
|
95
|
+
* blob.length -> length in bytes of the blob
|
96
|
+
*
|
97
|
+
* Returns the number of bytes in the blob.
|
98
|
+
*/
|
99
|
+
VALUE am_sqlite3_blob_length( VALUE self )
|
100
|
+
{
|
101
|
+
am_sqlite3_blob *am_blob;
|
102
|
+
int n;
|
103
|
+
|
104
|
+
Data_Get_Struct(self, am_sqlite3_blob, am_blob);
|
105
|
+
|
106
|
+
return INT2FIX( am_blob->length );
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* call-seq:
|
111
|
+
* blob.read( int ) -> String containting int number of bytes or nil if eof.
|
112
|
+
*
|
113
|
+
* returns int number of bytes as a String from the database
|
114
|
+
*/
|
115
|
+
VALUE am_sqlite3_blob_read( VALUE self, VALUE length )
|
116
|
+
{
|
117
|
+
am_sqlite3_blob *am_blob;
|
118
|
+
int rc;
|
119
|
+
int n = NUM2INT( length );
|
120
|
+
void *buf = NULL;
|
121
|
+
VALUE result;
|
122
|
+
|
123
|
+
Data_Get_Struct(self, am_sqlite3_blob, am_blob);
|
124
|
+
|
125
|
+
/* we have to be exact on the number of bytes to read. n + current_offset
|
126
|
+
* cannot be larger than the blob's length
|
127
|
+
*/
|
128
|
+
if ( (n + am_blob->current_offset > am_blob->length)) {
|
129
|
+
n = am_blob->length - am_blob->current_offset;
|
130
|
+
}
|
131
|
+
|
132
|
+
if ( am_blob->current_offset == am_blob->length ) {
|
133
|
+
return Qnil;
|
134
|
+
}
|
135
|
+
|
136
|
+
buf = (void *)malloc( n );
|
137
|
+
rc = sqlite3_blob_read( am_blob->blob, buf, n, am_blob->current_offset);
|
138
|
+
|
139
|
+
if ( rc != SQLITE_OK ) {
|
140
|
+
rb_raise(eAS_Error, "Error reading %d bytes blob at offset %d: [SQLITE_ERROR %d] %s\n",
|
141
|
+
n, am_blob->current_offset, rc, sqlite3_errmsg( am_blob->db ));
|
142
|
+
}
|
143
|
+
|
144
|
+
am_blob->current_offset += n;
|
145
|
+
|
146
|
+
result = rb_str_new( (char*)buf, n );
|
147
|
+
free( buf );
|
148
|
+
return result;
|
149
|
+
|
150
|
+
}
|
151
|
+
|
152
|
+
/**
|
153
|
+
* call-seq:
|
154
|
+
* blob.write( buf ) -> int
|
155
|
+
*
|
156
|
+
* writes the contents of the string buffer to the blob and returns the number
|
157
|
+
* of bytes written.
|
158
|
+
*
|
159
|
+
*/
|
160
|
+
VALUE am_sqlite3_blob_write( VALUE self, VALUE buf )
|
161
|
+
{
|
162
|
+
am_sqlite3_blob *am_blob;
|
163
|
+
int rc;
|
164
|
+
VALUE str = StringValue( buf );
|
165
|
+
int n = RSTRING( str )->len;
|
166
|
+
char *chk_buf = NULL;
|
167
|
+
|
168
|
+
Data_Get_Struct(self, am_sqlite3_blob, am_blob);
|
169
|
+
|
170
|
+
rc = sqlite3_blob_write( am_blob->blob, RSTRING(str)->ptr, n, am_blob->current_offset);
|
171
|
+
|
172
|
+
if ( rc != SQLITE_OK ) {
|
173
|
+
rb_raise(eAS_Error, "Error writing %d bytes blob at offset %d: [SQLITE_ERROR %d] %s\n",
|
174
|
+
n, am_blob->current_offset, rc, sqlite3_errmsg( am_blob->db ));
|
175
|
+
}
|
176
|
+
|
177
|
+
chk_buf = (char *) malloc( n + 1);
|
178
|
+
chk_buf[n] = '\0';
|
179
|
+
sqlite3_blob_read( am_blob->blob, chk_buf, n, 0);
|
180
|
+
|
181
|
+
am_blob->current_offset += n;
|
182
|
+
|
183
|
+
return INT2FIX( n );
|
184
|
+
|
185
|
+
}
|
186
|
+
|
187
|
+
|
188
|
+
/***********************************************************************
|
189
|
+
* Ruby life cycle methods
|
190
|
+
***********************************************************************/
|
191
|
+
|
192
|
+
/*
|
193
|
+
* garbage collector free method for the am_sqlite3_blob structure
|
194
|
+
*/
|
195
|
+
void am_sqlite3_blob_free(am_sqlite3_blob* wrapper)
|
196
|
+
{
|
197
|
+
free(wrapper);
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
|
201
|
+
/*
|
202
|
+
* allocate the am_blob structure
|
203
|
+
*/
|
204
|
+
VALUE am_sqlite3_blob_alloc(VALUE klass)
|
205
|
+
{
|
206
|
+
am_sqlite3_blob *wrapper = ALLOC(am_sqlite3_blob);
|
207
|
+
VALUE obj = (VALUE)NULL;
|
208
|
+
|
209
|
+
wrapper->current_offset = 0;
|
210
|
+
wrapper->db = NULL;
|
211
|
+
obj = Data_Wrap_Struct(klass, NULL, am_sqlite3_blob_free, wrapper);
|
212
|
+
return obj;
|
213
|
+
}
|
214
|
+
|
215
|
+
|
216
|
+
void Init_amalgalite3_blob( )
|
217
|
+
{
|
218
|
+
|
219
|
+
/** :stopdoc:
|
220
|
+
* These calls are here just to allow for rdoc generation
|
221
|
+
* :startdoc:
|
222
|
+
*/
|
223
|
+
VALUE ma = rb_define_module("Amalgalite");
|
224
|
+
VALUE mas = rb_define_module_under(ma, "SQLite3");
|
225
|
+
|
226
|
+
/*
|
227
|
+
* Encapsulate the SQLite3 Statement handle in a class
|
228
|
+
*/
|
229
|
+
cAS_Blob = rb_define_class_under( mas, "Blob", rb_cObject );
|
230
|
+
rb_define_alloc_func(cAS_Blob, am_sqlite3_blob_alloc);
|
231
|
+
rb_define_method(cAS_Blob, "initialize", am_sqlite3_blob_initialize, 6);
|
232
|
+
rb_define_method(cAS_Blob, "close", am_sqlite3_blob_close, 0);
|
233
|
+
rb_define_method(cAS_Blob, "read", am_sqlite3_blob_read, 1);
|
234
|
+
rb_define_method(cAS_Blob, "write", am_sqlite3_blob_write, 1);
|
235
|
+
rb_define_method(cAS_Blob, "length", am_sqlite3_blob_length, 0);
|
236
|
+
}
|
237
|
+
|
238
|
+
|
data/ext/amalgalite3_database.c
CHANGED
@@ -163,6 +163,42 @@ VALUE am_sqlite3_database_row_changes(VALUE self)
|
|
163
163
|
return INT2FIX(rc);
|
164
164
|
}
|
165
165
|
|
166
|
+
/**
|
167
|
+
* call-seq:
|
168
|
+
* database.last_error_code -> Integer
|
169
|
+
*
|
170
|
+
* return the last error code that happened in the database
|
171
|
+
*
|
172
|
+
*/
|
173
|
+
VALUE am_sqlite3_database_last_error_code(VALUE self)
|
174
|
+
{
|
175
|
+
am_sqlite3 *am_db;
|
176
|
+
int code;
|
177
|
+
|
178
|
+
Data_Get_Struct(self, am_sqlite3, am_db);
|
179
|
+
code = sqlite3_errcode( am_db->db );
|
180
|
+
|
181
|
+
return INT2FIX( code );
|
182
|
+
}
|
183
|
+
|
184
|
+
/**
|
185
|
+
* call-seq:
|
186
|
+
* database.last_error_message -> String
|
187
|
+
*
|
188
|
+
* return the last error message that happened in the database
|
189
|
+
*
|
190
|
+
*/
|
191
|
+
VALUE am_sqlite3_database_last_error_message(VALUE self)
|
192
|
+
{
|
193
|
+
am_sqlite3 *am_db;
|
194
|
+
const char *message;
|
195
|
+
|
196
|
+
Data_Get_Struct(self, am_sqlite3, am_db);
|
197
|
+
message = sqlite3_errmsg( am_db->db );
|
198
|
+
|
199
|
+
return rb_str_new2( message );
|
200
|
+
}
|
201
|
+
|
166
202
|
/**
|
167
203
|
* call-seq:
|
168
204
|
* database.total_changes -> Integer
|
@@ -211,6 +247,7 @@ VALUE am_sqlite3_database_prepare(VALUE self, VALUE rSQL)
|
|
211
247
|
|
212
248
|
if ( tail != NULL ) {
|
213
249
|
am_stmt->remaining_sql = rb_str_new2( tail );
|
250
|
+
rb_gc_register_address( &(am_stmt->remaining_sql) );
|
214
251
|
} else {
|
215
252
|
am_stmt->remaining_sql = Qnil;
|
216
253
|
}
|
@@ -453,6 +490,8 @@ void Init_amalgalite3_database( )
|
|
453
490
|
rb_define_method(cAS_Database, "table_column_metadata", am_sqlite3_database_table_column_metadata, 3); /* in amalgalite3_database.c */
|
454
491
|
rb_define_method(cAS_Database, "row_changes", am_sqlite3_database_row_changes, 0); /* in amalgalite3_database.c */
|
455
492
|
rb_define_method(cAS_Database, "total_changes", am_sqlite3_database_total_changes, 0); /* in amalgalite3_database.c */
|
493
|
+
rb_define_method(cAS_Database, "last_error_code", am_sqlite3_database_last_error_code, 0); /* in amalgalite3_database.c */
|
494
|
+
rb_define_method(cAS_Database, "last_error_message", am_sqlite3_database_last_error_message, 0); /* in amalgalite3_database.c */
|
456
495
|
|
457
496
|
}
|
458
497
|
|
data/ext/amalgalite3_statement.c
CHANGED
@@ -10,7 +10,7 @@ VALUE cAS_Statement; /* class Amalgliate::SQLite3::Statement */
|
|
10
10
|
|
11
11
|
/**
|
12
12
|
* call-seq:
|
13
|
-
* stmt.bind_null( position ) ->
|
13
|
+
* stmt.bind_null( position ) -> int
|
14
14
|
*
|
15
15
|
* bind a null value to the variable at postion.
|
16
16
|
*
|
@@ -31,6 +31,58 @@ VALUE am_sqlite3_statement_bind_null(VALUE self, VALUE position )
|
|
31
31
|
|
32
32
|
return INT2FIX(rc);
|
33
33
|
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* call-seq:
|
37
|
+
* stmt.bind_zeroblob( position, length ) -> int
|
38
|
+
*
|
39
|
+
* bind a blob with +length+ filled with zeros to the position. This is a Blob
|
40
|
+
* that will later filled in with incremental IO routines.
|
41
|
+
*/
|
42
|
+
VALUE am_sqlite3_statement_bind_zeroblob( VALUE self, VALUE position, VALUE length)
|
43
|
+
{
|
44
|
+
am_sqlite3_stmt *am_stmt;
|
45
|
+
int pos = FIX2INT( position );
|
46
|
+
int n = FIX2INT( length );
|
47
|
+
int rc;
|
48
|
+
|
49
|
+
Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
|
50
|
+
rc = sqlite3_bind_zeroblob( am_stmt->stmt, pos, n );
|
51
|
+
if ( SQLITE_OK != rc ) {
|
52
|
+
rb_raise(eAS_Error, "Error binding zeroblob of length %d at position %d in statement: [SQLITE_ERROR %d] : %s\n",
|
53
|
+
n, pos,
|
54
|
+
rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
|
55
|
+
}
|
56
|
+
|
57
|
+
return INT2FIX(rc);
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
/**
|
62
|
+
* call-seq:
|
63
|
+
* stmt.bind_blob( position, blob ) -> int
|
64
|
+
*
|
65
|
+
* bind a blob to the variable at position. This is a blob that is fully held
|
66
|
+
* in memory
|
67
|
+
*/
|
68
|
+
VALUE am_sqlite3_statement_bind_blob( VALUE self, VALUE position, VALUE blob )
|
69
|
+
{
|
70
|
+
am_sqlite3_stmt *am_stmt;
|
71
|
+
int pos = FIX2INT( position );
|
72
|
+
VALUE str = StringValue( blob );
|
73
|
+
int rc;
|
74
|
+
|
75
|
+
Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
|
76
|
+
rc = sqlite3_bind_blob( am_stmt->stmt, pos, RSTRING( str )->ptr, RSTRING( str )->len, SQLITE_TRANSIENT);
|
77
|
+
if ( SQLITE_OK != rc ) {
|
78
|
+
rb_raise(eAS_Error, "Error binding blob at position %d in statement: [SQLITE_ERROR %d] : %s\n",
|
79
|
+
pos,
|
80
|
+
rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
|
81
|
+
}
|
82
|
+
|
83
|
+
return INT2FIX(rc);
|
84
|
+
}
|
85
|
+
|
34
86
|
/**
|
35
87
|
* call-seq:
|
36
88
|
* stmt.bind_double( position, value ) -> nil
|
@@ -121,7 +173,7 @@ VALUE am_sqlite3_statement_bind_text(VALUE self, VALUE position, VALUE value)
|
|
121
173
|
int rc;
|
122
174
|
|
123
175
|
Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
|
124
|
-
rc = sqlite3_bind_text( am_stmt->stmt, pos, RSTRING(str)->ptr, RSTRING(str)->len,
|
176
|
+
rc = sqlite3_bind_text( am_stmt->stmt, pos, RSTRING(str)->ptr, RSTRING(str)->len, SQLITE_TRANSIENT);
|
125
177
|
if ( SQLITE_OK != rc ) {
|
126
178
|
rb_raise(eAS_Error, "Error binding [%s] to text at position %d in statement: [SQLITE_ERROR %d] : %s\n",
|
127
179
|
RSTRING(str)->ptr, pos,
|
@@ -324,6 +376,28 @@ VALUE am_sqlite3_statement_column_text(VALUE self, VALUE v_idx)
|
|
324
376
|
return rb_str_new2( (const char*)sqlite3_column_text( am_stmt->stmt, idx ) );
|
325
377
|
}
|
326
378
|
|
379
|
+
/**
|
380
|
+
* call-seq:
|
381
|
+
* stmt.column_blob( index ) -> String
|
382
|
+
*
|
383
|
+
* Return the data in ith column of the result as a String.
|
384
|
+
*
|
385
|
+
*/
|
386
|
+
VALUE am_sqlite3_statement_column_blob(VALUE self, VALUE v_idx)
|
387
|
+
{
|
388
|
+
am_sqlite3_stmt *am_stmt;
|
389
|
+
int idx = FIX2INT( v_idx );
|
390
|
+
const char *data;
|
391
|
+
long length;
|
392
|
+
|
393
|
+
Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
|
394
|
+
data = sqlite3_column_blob( am_stmt->stmt, idx );
|
395
|
+
length = sqlite3_column_bytes( am_stmt->stmt, idx );
|
396
|
+
return rb_str_new( data, length );
|
397
|
+
|
398
|
+
}
|
399
|
+
|
400
|
+
|
327
401
|
/**
|
328
402
|
* call-seq:
|
329
403
|
* stmt.column_double( index ) -> Float
|
@@ -470,6 +544,8 @@ VALUE am_sqlite3_statement_close( VALUE self )
|
|
470
544
|
rb_raise(eAS_Error, "Failure to close statment : [SQLITE_ERROR %d] : %s\n",
|
471
545
|
rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
|
472
546
|
}
|
547
|
+
|
548
|
+
return Qnil;
|
473
549
|
}
|
474
550
|
|
475
551
|
/***********************************************************************
|
@@ -483,6 +559,10 @@ VALUE am_sqlite3_statement_close( VALUE self )
|
|
483
559
|
void am_sqlite3_statement_free(am_sqlite3_stmt* wrapper)
|
484
560
|
{
|
485
561
|
|
562
|
+
if ( Qnil != wrapper->remaining_sql ) {
|
563
|
+
rb_gc_unregister_address( &(wrapper->remaining_sql) );
|
564
|
+
wrapper->remaining_sql = Qnil;
|
565
|
+
}
|
486
566
|
free(wrapper);
|
487
567
|
return;
|
488
568
|
}
|
@@ -524,6 +604,7 @@ void Init_amalgalite3_statement( )
|
|
524
604
|
rb_define_method(cAS_Statement, "column_declared_type", am_sqlite3_statement_column_decltype, 1);
|
525
605
|
rb_define_method(cAS_Statement, "column_type", am_sqlite3_statement_column_type, 1);
|
526
606
|
rb_define_method(cAS_Statement, "column_text", am_sqlite3_statement_column_text, 1);
|
607
|
+
rb_define_method(cAS_Statement, "column_blob", am_sqlite3_statement_column_blob, 1);
|
527
608
|
rb_define_method(cAS_Statement, "column_int", am_sqlite3_statement_column_int, 1);
|
528
609
|
rb_define_method(cAS_Statement, "column_int64", am_sqlite3_statement_column_int64, 1);
|
529
610
|
rb_define_method(cAS_Statement, "column_double", am_sqlite3_statement_column_double, 1);
|
@@ -541,6 +622,8 @@ void Init_amalgalite3_statement( )
|
|
541
622
|
rb_define_method(cAS_Statement, "bind_int64", am_sqlite3_statement_bind_int64, 2);
|
542
623
|
rb_define_method(cAS_Statement, "bind_double", am_sqlite3_statement_bind_double, 2);
|
543
624
|
rb_define_method(cAS_Statement, "bind_null", am_sqlite3_statement_bind_null, 1);
|
625
|
+
rb_define_method(cAS_Statement, "bind_blob", am_sqlite3_statement_bind_blob, 2);
|
626
|
+
rb_define_method(cAS_Statement, "bind_zeroblob", am_sqlite3_statement_bind_zeroblob, 2);
|
544
627
|
}
|
545
628
|
|
546
629
|
|