amalgalite 0.10.1-x86-mingw32

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.
Files changed (100) hide show
  1. data/HISTORY +201 -0
  2. data/LICENSE +29 -0
  3. data/README +51 -0
  4. data/bin/amalgalite-pack +126 -0
  5. data/examples/a.rb +9 -0
  6. data/examples/blob.rb +88 -0
  7. data/examples/bootstrap.rb +36 -0
  8. data/examples/define_aggregate.rb +75 -0
  9. data/examples/define_function.rb +104 -0
  10. data/examples/gem-db.rb +94 -0
  11. data/examples/gems.db +0 -0
  12. data/examples/require_me.rb +11 -0
  13. data/examples/requires.rb +42 -0
  14. data/examples/schema-info.rb +34 -0
  15. data/ext/amalgalite/amalgalite3.c +290 -0
  16. data/ext/amalgalite/amalgalite3.h +151 -0
  17. data/ext/amalgalite/amalgalite3_blob.c +240 -0
  18. data/ext/amalgalite/amalgalite3_constants.c +221 -0
  19. data/ext/amalgalite/amalgalite3_database.c +1148 -0
  20. data/ext/amalgalite/amalgalite3_requires_bootstrap.c +210 -0
  21. data/ext/amalgalite/amalgalite3_statement.c +639 -0
  22. data/ext/amalgalite/extconf.rb +36 -0
  23. data/ext/amalgalite/gen_constants.rb +130 -0
  24. data/ext/amalgalite/sqlite3.c +106729 -0
  25. data/ext/amalgalite/sqlite3.h +5626 -0
  26. data/ext/amalgalite/sqlite3_options.h +4 -0
  27. data/ext/amalgalite/sqlite3ext.h +380 -0
  28. data/gemspec.rb +60 -0
  29. data/lib/amalgalite.rb +43 -0
  30. data/lib/amalgalite/1.8/amalgalite3.so +0 -0
  31. data/lib/amalgalite/1.9/amalgalite3.so +0 -0
  32. data/lib/amalgalite/aggregate.rb +67 -0
  33. data/lib/amalgalite/blob.rb +186 -0
  34. data/lib/amalgalite/boolean.rb +42 -0
  35. data/lib/amalgalite/busy_timeout.rb +47 -0
  36. data/lib/amalgalite/column.rb +97 -0
  37. data/lib/amalgalite/core_ext/kernel/require.rb +21 -0
  38. data/lib/amalgalite/database.rb +947 -0
  39. data/lib/amalgalite/function.rb +61 -0
  40. data/lib/amalgalite/index.rb +43 -0
  41. data/lib/amalgalite/packer.rb +226 -0
  42. data/lib/amalgalite/paths.rb +70 -0
  43. data/lib/amalgalite/profile_tap.rb +131 -0
  44. data/lib/amalgalite/progress_handler.rb +21 -0
  45. data/lib/amalgalite/requires.rb +120 -0
  46. data/lib/amalgalite/schema.rb +191 -0
  47. data/lib/amalgalite/sqlite3.rb +6 -0
  48. data/lib/amalgalite/sqlite3/constants.rb +80 -0
  49. data/lib/amalgalite/sqlite3/database/function.rb +48 -0
  50. data/lib/amalgalite/sqlite3/database/status.rb +68 -0
  51. data/lib/amalgalite/sqlite3/status.rb +60 -0
  52. data/lib/amalgalite/sqlite3/version.rb +37 -0
  53. data/lib/amalgalite/statement.rb +414 -0
  54. data/lib/amalgalite/table.rb +90 -0
  55. data/lib/amalgalite/taps.rb +2 -0
  56. data/lib/amalgalite/taps/console.rb +27 -0
  57. data/lib/amalgalite/taps/io.rb +71 -0
  58. data/lib/amalgalite/trace_tap.rb +35 -0
  59. data/lib/amalgalite/type_map.rb +63 -0
  60. data/lib/amalgalite/type_maps/default_map.rb +167 -0
  61. data/lib/amalgalite/type_maps/storage_map.rb +40 -0
  62. data/lib/amalgalite/type_maps/text_map.rb +22 -0
  63. data/lib/amalgalite/version.rb +37 -0
  64. data/lib/amalgalite/view.rb +26 -0
  65. data/spec/aggregate_spec.rb +169 -0
  66. data/spec/amalgalite_spec.rb +4 -0
  67. data/spec/blob_spec.rb +81 -0
  68. data/spec/boolean_spec.rb +23 -0
  69. data/spec/busy_handler.rb +165 -0
  70. data/spec/database_spec.rb +494 -0
  71. data/spec/default_map_spec.rb +87 -0
  72. data/spec/function_spec.rb +94 -0
  73. data/spec/integeration_spec.rb +111 -0
  74. data/spec/packer_spec.rb +60 -0
  75. data/spec/paths_spec.rb +28 -0
  76. data/spec/progress_handler_spec.rb +105 -0
  77. data/spec/requires_spec.rb +23 -0
  78. data/spec/rtree_spec.rb +71 -0
  79. data/spec/schema_spec.rb +120 -0
  80. data/spec/spec_helper.rb +27 -0
  81. data/spec/sqlite3/constants_spec.rb +65 -0
  82. data/spec/sqlite3/database_status_spec.rb +36 -0
  83. data/spec/sqlite3/status_spec.rb +18 -0
  84. data/spec/sqlite3/version_spec.rb +14 -0
  85. data/spec/sqlite3_spec.rb +53 -0
  86. data/spec/statement_spec.rb +161 -0
  87. data/spec/storage_map_spec.rb +41 -0
  88. data/spec/tap_spec.rb +59 -0
  89. data/spec/text_map_spec.rb +23 -0
  90. data/spec/type_map_spec.rb +17 -0
  91. data/spec/version_spec.rb +15 -0
  92. data/tasks/announce.rake +43 -0
  93. data/tasks/config.rb +107 -0
  94. data/tasks/distribution.rake +77 -0
  95. data/tasks/documentation.rake +32 -0
  96. data/tasks/extension.rake +141 -0
  97. data/tasks/rspec.rake +33 -0
  98. data/tasks/rubyforge.rake +59 -0
  99. data/tasks/utils.rb +80 -0
  100. metadata +237 -0
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Copyright (c) 2008 Jeremy Hinegardner
3
+ * All rights reserved. See LICENSE and/or COPYING for details.
4
+ *
5
+ * vim: shiftwidth=4
6
+ */
7
+
8
+ #include "amalgalite3.h"
9
+ #include <stdio.h>
10
+ extern VALUE mA;
11
+ VALUE cAR;
12
+ VALUE cARB;
13
+ VALUE eARB_Error;
14
+
15
+ /*
16
+ * cleanup the datatbase and statment values if they are currently open and then
17
+ * raise the message. It converts the error message to a String so that the C
18
+ * string can be free'd and then raise with a ruby object in the hopes that
19
+ * there is no memory leak from the C allocation.
20
+ */
21
+ void am_bootstrap_cleanup_and_raise( char* msg, sqlite3* db, sqlite3_stmt* stmt )
22
+ {
23
+
24
+ if ( NULL != stmt ) { sqlite3_finalize( stmt ); }
25
+ if ( NULL != db ) { sqlite3_close( db ); }
26
+
27
+ free( msg );
28
+ rb_raise(eARB_Error, msg );
29
+ }
30
+
31
+
32
+ /**
33
+ * call-seq:
34
+ * Amalgalite::Requires::Bootstrap.lift( 'dbfile' => "lib.db", 'table_name' => "bootload", 'rowid_column' => "id", 'filename_column' => "filename", 'content_column' => "contents" )
35
+ *
36
+ * *WARNING* *WARNING* *WARNING* *WARNING* *WARNING* *WARNING* *WARNING*
37
+ *
38
+ * This is a boostrap mechanism to eval all the code in a particular column in a
39
+ * specially formatted table in an sqlite database. It should only be used for
40
+ * a specific purpose, mainly loading the Amalgalite ruby code directly from an
41
+ * sqlite table.
42
+ *
43
+ * Amalgalite::Requires adds in the ability to _require_ code that is in an
44
+ * sqlite database. Since Amalgalite::Requires is itself ruby code, if
45
+ * Amalgalite::Requires was in an sqlite database, it could not _require_
46
+ * itself. Therefore this method is made available. It is a pure C extension
47
+ * method that directly calls the sqlite3 C functions directly and uses the ruby
48
+ * C api to eval the data in the table.
49
+ *
50
+ * This method attaches to an sqlite3 database (filename) and then does:
51
+ *
52
+ * SELECT filename_column_name, content_column_name
53
+ * FROM table_name
54
+ * ORDER BY rowid_column_name
55
+ *
56
+ * For each row returned it does an _eval_ on the code in the
57
+ * *content_column_name* and then updates _$LOADED_FEATURES_ directly with the value from
58
+ * *filename_column_name*.
59
+ *
60
+ * The database to be opened by _lift_ *must* be an sqlite3 UTF-8 database.
61
+ *
62
+ */
63
+ VALUE am_bootstrap_lift( VALUE self, VALUE args )
64
+ {
65
+ sqlite3* db = NULL;
66
+ sqlite3_stmt* stmt = NULL;
67
+ int rc;
68
+ int last_row_good;
69
+ char raise_msg[BUFSIZ];
70
+
71
+ VALUE am_db_c = rb_const_get( cARB, rb_intern("DEFAULT_DB") );
72
+ VALUE am_tbl_c = rb_const_get( cARB, rb_intern("DEFAULT_BOOTSTRAP_TABLE") );
73
+ VALUE am_pk_c = rb_const_get( cARB, rb_intern("DEFAULT_ROWID_COLUMN") );
74
+ VALUE am_fname_c = rb_const_get( cARB, rb_intern("DEFAULT_FILENAME_COLUMN") );
75
+ VALUE am_content_c = rb_const_get( cARB, rb_intern("DEFAULT_CONTENTS_COLUMN") );
76
+
77
+ char* dbfile = NULL;
78
+ char* tbl_name = NULL;
79
+ char* pk_col = NULL;
80
+ char* fname_col = NULL;
81
+ char* content_col = NULL;
82
+
83
+ char sql[BUFSIZ];
84
+ const char* sql_tail = NULL;
85
+ int sql_bytes = 0;
86
+
87
+ const unsigned char* result_text = NULL;
88
+ int result_length = 0;
89
+
90
+ VALUE require_name = Qnil; /* ruby string of the file name for use in eval */
91
+ VALUE eval_this_code = Qnil; /* ruby string of the code to eval from the db */
92
+ VALUE toplevel_binding = rb_const_get( rb_cObject, rb_intern("TOPLEVEL_BINDING") ) ;
93
+ VALUE tmp = Qnil;
94
+
95
+ ID eval_id = rb_intern("eval");
96
+
97
+
98
+ if ( Qnil == args ) {
99
+ args = rb_hash_new();
100
+ } else {
101
+ args = rb_ary_shift( args );
102
+ }
103
+
104
+ Check_Type( args, T_HASH );
105
+
106
+ /* get the arguments */
107
+ dbfile = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "dbfile" ) ) ) ) ? StringValuePtr( am_db_c ) : StringValuePtr( tmp );
108
+ tbl_name = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "table_name" ) ) ) ) ? StringValuePtr( am_tbl_c ) : StringValuePtr( tmp );
109
+ pk_col = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "rowid_column" ) ) ) ) ? StringValuePtr( am_pk_c ) : StringValuePtr( tmp );
110
+ fname_col = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "filename_column" ) ) ) ) ? StringValuePtr( am_fname_c ) : StringValuePtr( tmp );
111
+ content_col = ( Qnil == (tmp = rb_hash_aref( args, rb_str_new2( "contents_column" ) ) ) ) ? StringValuePtr( am_content_c ) : StringValuePtr( tmp );
112
+
113
+
114
+ /* open the database */
115
+ rc = sqlite3_open_v2( dbfile , &db, SQLITE_OPEN_READONLY, NULL);
116
+ if ( SQLITE_OK != rc ) {
117
+ memset( raise_msg, 0, BUFSIZ );
118
+ snprintf(raise_msg, BUFSIZ, "Failure to open database %s for bootload: [SQLITE_ERROR %d] : %s", dbfile, rc, sqlite3_errmsg( db ) );
119
+ am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
120
+ }
121
+
122
+ /* prepare the db query */
123
+ memset( sql, 0, BUFSIZ );
124
+ sql_bytes = snprintf( sql, BUFSIZ, "SELECT %s, %s FROM %s ORDER BY %s", fname_col, content_col, tbl_name, pk_col );
125
+ rc = sqlite3_prepare_v2( db, sql, sql_bytes, &stmt, &sql_tail ) ;
126
+ if ( SQLITE_OK != rc) {
127
+ memset( raise_msg, 0, BUFSIZ );
128
+ snprintf( raise_msg, BUFSIZ,
129
+ "Failure to prepare bootload select statement table = '%s', rowid col = '%s', filename col ='%s', contents col = '%s' : [SQLITE_ERROR %d] %s\n",
130
+ tbl_name, pk_col, fname_col, content_col, rc, sqlite3_errmsg( db ));
131
+ am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
132
+ }
133
+
134
+ /* loop over the resulting rows, eval'ing and loading $LOADED_FEATURES */
135
+ last_row_good = -1;
136
+ while ( SQLITE_ROW == ( rc = sqlite3_step( stmt ) ) ) {
137
+ /* file name */
138
+ result_text = sqlite3_column_text( stmt, 0 );
139
+ result_length = sqlite3_column_bytes( stmt, 0 );
140
+ require_name = rb_str_new( (const char*)result_text, result_length );
141
+
142
+ /* ruby code */
143
+ result_text = sqlite3_column_text( stmt, 1 );
144
+ result_length = sqlite3_column_bytes( stmt, 1 );
145
+ eval_this_code = rb_str_new( (const char*)result_text, result_length );
146
+
147
+ /* Kernel.eval( code, TOPLEVEL_BINDING, filename, 1 ) */
148
+ rb_funcall(rb_mKernel, eval_id, 4, eval_this_code, toplevel_binding, require_name, INT2FIX(1) );
149
+
150
+ /* TODO: for ruby 1.9 -- put in ? sqlite3://path/to/database?tablename=tbl_name#require_name */
151
+ /* update $LOADED_FEATURES */
152
+ rb_ary_push( rb_gv_get( "$LOADED_FEATURES" ), require_name );
153
+ }
154
+
155
+ /* if there was some sqlite error in the processing of the rows */
156
+ if ( SQLITE_DONE != rc ) {
157
+ memset( raise_msg, 0, BUFSIZ );
158
+ snprintf( raise_msg, BUFSIZ, "Failure in bootloading, last successfully loaded rowid was %d : [SQLITE_ERROR %d] %s\n",
159
+ last_row_good, rc, sqlite3_errmsg( db ) );
160
+ am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
161
+ }
162
+
163
+ /* finalize the statement */
164
+ rc = sqlite3_finalize( stmt );
165
+ if ( SQLITE_OK != rc ) {
166
+ memset( raise_msg, 0, BUFSIZ );
167
+ snprintf( raise_msg, BUFSIZ, "Failure to finalize bootload statement : [SQLITE_ERROR %d] %s\n", rc, sqlite3_errmsg( db ) );
168
+ am_bootstrap_cleanup_and_raise( raise_msg, db, stmt );
169
+ }
170
+
171
+ stmt = NULL;
172
+
173
+ /* close the database */
174
+ rc = sqlite3_close( db );
175
+ if ( SQLITE_OK != rc ) {
176
+ memset( raise_msg, 0, BUFSIZ );
177
+ snprintf( raise_msg, BUFSIZ, "Failure to close database : [SQLITE_ERROR %d] : %s\n", rc, sqlite3_errmsg( db )),
178
+ am_bootstrap_cleanup_and_raise( raise_msg, db,stmt );
179
+ }
180
+
181
+ return Qnil;
182
+ }
183
+
184
+ /**
185
+ * Bootstrapping module to help _require_ when Amalgalite::Requires is not
186
+ * availble in files.
187
+ */
188
+ void Init_amalgalite3_requires_bootstrap()
189
+ {
190
+
191
+ mA = rb_define_module("Amalgalite");
192
+ cAR = rb_define_class_under(mA, "Requires", rb_cObject);
193
+ cARB = rb_define_class_under(cAR, "Bootstrap", rb_cObject);
194
+
195
+ eARB_Error = rb_define_class_under(cARB, "Error", rb_eStandardError);
196
+
197
+ rb_define_module_function(cARB, "lift", am_bootstrap_lift, -2);
198
+
199
+ /* constants for default db, table, column, rowid, contents */
200
+ rb_define_const(cARB, "DEFAULT_DB", rb_str_new2( "lib.db" ));
201
+ rb_define_const(cARB, "DEFAULT_TABLE", rb_str_new2( "rubylibs" ));
202
+ rb_define_const(cARB, "DEFAULT_BOOTSTRAP_TABLE", rb_str_new2( "bootstrap" ));
203
+ rb_define_const(cARB, "DEFAULT_ROWID_COLUMN", rb_str_new2( "id" ));
204
+ rb_define_const(cARB, "DEFAULT_FILENAME_COLUMN", rb_str_new2( "filename" ));
205
+ rb_define_const(cARB, "DEFAULT_CONTENTS_COLUMN", rb_str_new2( "contents" ));
206
+ rb_define_const(cARB, "DEFAULT_COMPRESSED_COLUMN", rb_str_new2( "compressed" ));
207
+
208
+ return;
209
+ }
210
+
@@ -0,0 +1,639 @@
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_Statement; /* class Amalgliate::SQLite3::Statement */
10
+
11
+ /**
12
+ * call-seq:
13
+ * stmt.bind_null( position ) -> int
14
+ *
15
+ * bind a null value to the variable at postion.
16
+ *
17
+ */
18
+ VALUE am_sqlite3_statement_bind_null(VALUE self, VALUE position )
19
+ {
20
+ am_sqlite3_stmt *am_stmt;
21
+ int pos = FIX2INT( position );
22
+ int rc;
23
+
24
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
25
+ rc = sqlite3_bind_null( am_stmt->stmt, pos );
26
+ if ( SQLITE_OK != rc ) {
27
+ rb_raise(eAS_Error, "Error binding NULL at position %d in statement: [SQLITE_ERROR %d] : %s\n",
28
+ pos,
29
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
30
+ }
31
+
32
+ return INT2FIX(rc);
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_PTR( str ), RSTRING_LEN( str ), 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
+
86
+ /**
87
+ * call-seq:
88
+ * stmt.bind_double( position, value ) -> nil
89
+ *
90
+ * bind a double value to the variable at postion.
91
+ *
92
+ */
93
+ VALUE am_sqlite3_statement_bind_double(VALUE self, VALUE position, VALUE value)
94
+ {
95
+ am_sqlite3_stmt *am_stmt;
96
+ int pos = FIX2INT( position );
97
+ double v = NUM2DBL( value );
98
+ int rc;
99
+
100
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
101
+ rc = sqlite3_bind_double( am_stmt->stmt, pos, v );
102
+ if ( SQLITE_OK != rc ) {
103
+ rb_raise(eAS_Error, "Error binding [%lf] to double at position %d in statement: [SQLITE_ERROR %d] : %s\n",
104
+ v, pos,
105
+ rc, (char*)sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
106
+ }
107
+
108
+ return INT2FIX(rc);
109
+ }
110
+
111
+ /**
112
+ * call-seq:
113
+ * stmt.bind_int( position, value ) -> nil
114
+ *
115
+ * bind a int value to the variable at postion.
116
+ *
117
+ */
118
+ VALUE am_sqlite3_statement_bind_int(VALUE self, VALUE position, VALUE value)
119
+ {
120
+ am_sqlite3_stmt *am_stmt;
121
+ int pos = FIX2INT( position );
122
+ int v = NUM2INT( value );
123
+ int rc;
124
+
125
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
126
+ rc = sqlite3_bind_int( am_stmt->stmt, pos, v );
127
+ if ( SQLITE_OK != rc ) {
128
+ rb_raise(eAS_Error, "Error binding [%d] to int at position %d in statement: [SQLITE_ERROR %d] : %s\n",
129
+ v, pos,
130
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
131
+ }
132
+
133
+ return INT2FIX(rc);
134
+ }
135
+
136
+ /**
137
+ * call-seq:
138
+ * stmt.bind_int64( position, value ) -> nil
139
+ *
140
+ * bind a int64 value to the variable at postion.
141
+ *
142
+ */
143
+ VALUE am_sqlite3_statement_bind_int64(VALUE self, VALUE position, VALUE value)
144
+ {
145
+ am_sqlite3_stmt *am_stmt;
146
+ int pos = FIX2INT( position );
147
+ sqlite3_int64 v = NUM2SQLINT64( value );
148
+ int rc;
149
+
150
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
151
+ rc = sqlite3_bind_int64( am_stmt->stmt, pos, v );
152
+ if ( SQLITE_OK != rc ) {
153
+ rb_raise(eAS_Error, "Error binding [%lld] to int64 at position %d in statement: [SQLITE_ERROR %d] : %s\n",
154
+ v, pos,
155
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
156
+ }
157
+
158
+ return INT2FIX(rc);
159
+ }
160
+
161
+ /**
162
+ * call-seq:
163
+ * stmt.bind_text( position, value ) -> nil
164
+ *
165
+ * bind a string value to the variable at postion.
166
+ *
167
+ */
168
+ VALUE am_sqlite3_statement_bind_text(VALUE self, VALUE position, VALUE value)
169
+ {
170
+ am_sqlite3_stmt *am_stmt;
171
+ int pos = FIX2INT( position );
172
+ VALUE str = StringValue( value );
173
+ int rc;
174
+
175
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
176
+ rc = sqlite3_bind_text( am_stmt->stmt, pos, RSTRING_PTR(str), RSTRING_LEN(str), SQLITE_TRANSIENT);
177
+ if ( SQLITE_OK != rc ) {
178
+ rb_raise(eAS_Error, "Error binding [%s] to text at position %d in statement: [SQLITE_ERROR %d] : %s\n",
179
+ RSTRING_PTR(str), pos,
180
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
181
+ }
182
+
183
+ return INT2FIX(rc);
184
+ }
185
+ /**
186
+ * call-seq:
187
+ * stmt.remaining_sql -> String
188
+ *
189
+ * returns the remainging SQL leftover from the initialization sql, or nil if
190
+ * there is no remaining SQL
191
+ */
192
+ VALUE am_sqlite3_statement_remaining_sql(VALUE self)
193
+ {
194
+ am_sqlite3_stmt *am_stmt;
195
+
196
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
197
+ return am_stmt->remaining_sql;
198
+ }
199
+ /**
200
+ * call-seq:
201
+ * stmt.parameter_index( name ) -> Integer
202
+ *
203
+ * returns the index of the named parameter from the statement. Used to help
204
+ * with the :VVV, @VVV and $VVV pareamter replacement styles.
205
+ */
206
+ VALUE am_sqlite3_statement_bind_parameter_index(VALUE self, VALUE parameter_name)
207
+ {
208
+ am_sqlite3_stmt *am_stmt;
209
+ int idx;
210
+
211
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
212
+ idx = sqlite3_bind_parameter_index( am_stmt->stmt, StringValuePtr( parameter_name ));
213
+ return INT2FIX( idx );
214
+ }
215
+
216
+ /**
217
+ * call-seq:
218
+ * stmt.parameter_count -> Integer
219
+ *
220
+ * return the index of the largest parameter in the in the statement. For all
221
+ * forms except ?NNN this is the number of unique parameters. Using ?NNN can
222
+ * create gaps in the list of parameters.
223
+ *
224
+ */
225
+ VALUE am_sqlite3_statement_bind_parameter_count(VALUE self)
226
+ {
227
+ am_sqlite3_stmt *am_stmt;
228
+
229
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
230
+ return INT2FIX(sqlite3_bind_parameter_count( am_stmt->stmt ) );
231
+ }
232
+
233
+ /**
234
+ * call-seq:
235
+ * stmt.reset! -> nil
236
+ *
237
+ * reset the SQLite3 statement back to its initial state.
238
+ */
239
+ VALUE am_sqlite3_statement_reset(VALUE self)
240
+ {
241
+ am_sqlite3_stmt *am_stmt;
242
+ int rc;
243
+
244
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
245
+ rc = sqlite3_reset( am_stmt->stmt );
246
+ if ( rc != SQLITE_OK ) {
247
+ rb_raise(eAS_Error, "Error resetting statement: [SQLITE_ERROR %d] : %s\n",
248
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
249
+ }
250
+ return Qnil;
251
+ }
252
+
253
+ /**
254
+ * call-seq:
255
+ * stmt.clear_bindings! -> nil
256
+ *
257
+ * reset the SQLite3 statement back to its initial state.
258
+ */
259
+ VALUE am_sqlite3_statement_clear_bindings(VALUE self)
260
+ {
261
+ am_sqlite3_stmt *am_stmt;
262
+ int rc;
263
+
264
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
265
+ rc = sqlite3_clear_bindings( am_stmt->stmt );
266
+ if ( rc != SQLITE_OK ) {
267
+ rb_raise(eAS_Error, "Error resetting statement: [SQLITE_ERROR %d] : %s\n",
268
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
269
+ }
270
+ return Qnil;
271
+ }
272
+
273
+
274
+ /**
275
+ * call-seq:
276
+ * stmt.step -> int
277
+ *
278
+ * Step through the next piece of the SQLite3 statement
279
+ *
280
+ */
281
+ VALUE am_sqlite3_statement_step(VALUE self)
282
+ {
283
+ am_sqlite3_stmt *am_stmt;
284
+
285
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
286
+ return INT2FIX( sqlite3_step( am_stmt->stmt ) );
287
+ }
288
+
289
+ /**
290
+ * call-seq:
291
+ * stmt.column_count -> Fixnum
292
+ *
293
+ * return the number of columns in the result set.
294
+ *
295
+ */
296
+ VALUE am_sqlite3_statement_column_count(VALUE self)
297
+ {
298
+ am_sqlite3_stmt *am_stmt;
299
+
300
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
301
+ return INT2FIX( sqlite3_column_count( am_stmt->stmt ) );
302
+ }
303
+
304
+ /**
305
+ * call-seq:
306
+ * stmt.column_name( index ) -> String
307
+ *
308
+ * Return the column name at the ith column in the result set. The left-most column
309
+ * is number 0.
310
+ *
311
+ */
312
+ VALUE am_sqlite3_statement_column_name(VALUE self, VALUE v_idx)
313
+ {
314
+ am_sqlite3_stmt *am_stmt;
315
+ int idx = FIX2INT( v_idx );
316
+
317
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
318
+
319
+ return rb_str_new2( sqlite3_column_name( am_stmt->stmt, idx ) );
320
+ }
321
+
322
+
323
+ /**
324
+ * call-seq:
325
+ * stmt.column_declared_type( index ) -> String
326
+ *
327
+ * Return the declared type of the ith column in the result set. This is the
328
+ * value that was in the original CREATE TABLE statement.
329
+ *
330
+ */
331
+ VALUE am_sqlite3_statement_column_decltype(VALUE self, VALUE v_idx)
332
+ {
333
+ am_sqlite3_stmt *am_stmt;
334
+ int idx = FIX2INT( v_idx );
335
+ const char *decltype;
336
+
337
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
338
+ decltype = sqlite3_column_decltype( am_stmt->stmt, idx ) ;
339
+ if ( NULL == decltype) {
340
+ return Qnil;
341
+ } else {
342
+ return rb_str_new2( decltype );
343
+ }
344
+ }
345
+
346
+ /**
347
+ * call-seq:
348
+ * stmt.column_type( index ) -> SQLite3::DataType constant
349
+ *
350
+ * Return the column type at the ith column in the result set. The left-most column
351
+ * is number 0.
352
+ *
353
+ */
354
+ VALUE am_sqlite3_statement_column_type(VALUE self, VALUE v_idx)
355
+ {
356
+ am_sqlite3_stmt *am_stmt;
357
+ int idx = FIX2INT( v_idx );
358
+
359
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
360
+ return INT2FIX( sqlite3_column_type( am_stmt->stmt, idx ) );
361
+ }
362
+
363
+ /**
364
+ * call-seq:
365
+ * stmt.column_text( index ) -> String
366
+ *
367
+ * Return the data in ith column of the result as a String.
368
+ *
369
+ */
370
+ VALUE am_sqlite3_statement_column_text(VALUE self, VALUE v_idx)
371
+ {
372
+ am_sqlite3_stmt *am_stmt;
373
+ int idx = FIX2INT( v_idx );
374
+
375
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
376
+ return rb_str_new2( (const char*)sqlite3_column_text( am_stmt->stmt, idx ) );
377
+ }
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
+
401
+ /**
402
+ * call-seq:
403
+ * stmt.column_double( index ) -> Float
404
+ *
405
+ * Return the data in ith column of the result as an Float
406
+ *
407
+ */
408
+ VALUE am_sqlite3_statement_column_double(VALUE self, VALUE v_idx)
409
+ {
410
+ am_sqlite3_stmt *am_stmt;
411
+ int idx = FIX2INT( v_idx );
412
+
413
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
414
+ return rb_float_new( sqlite3_column_double( am_stmt->stmt, idx )) ;
415
+ }
416
+
417
+
418
+ /**
419
+ * call-seq:
420
+ * stmt.column_int( index ) -> Integer
421
+ *
422
+ * Return the data in ith column of the result as an Integer
423
+ *
424
+ */
425
+ VALUE am_sqlite3_statement_column_int(VALUE self, VALUE v_idx)
426
+ {
427
+ am_sqlite3_stmt *am_stmt;
428
+ int idx = FIX2INT( v_idx );
429
+
430
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
431
+ return INT2NUM( sqlite3_column_int( am_stmt->stmt, idx )) ;
432
+ }
433
+
434
+
435
+ /**
436
+ * call-seq:
437
+ * stmt.column_int64( index ) -> Integer
438
+ *
439
+ * Return the data in ith column of the result as an Integer
440
+ *
441
+ */
442
+ VALUE am_sqlite3_statement_column_int64(VALUE self, VALUE v_idx)
443
+ {
444
+ am_sqlite3_stmt *am_stmt;
445
+ int idx = FIX2INT( v_idx );
446
+
447
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
448
+ return SQLINT64_2NUM( sqlite3_column_int64( am_stmt->stmt, idx )) ;
449
+ }
450
+
451
+
452
+
453
+ /**
454
+ * call-seq:
455
+ * stmt.column_database_name( index ) -> String
456
+ *
457
+ * Return the database name where the data in the ith column of the result set
458
+ * comes from.
459
+ *
460
+ */
461
+ VALUE am_sqlite3_statement_column_database_name(VALUE self, VALUE v_idx)
462
+ {
463
+ am_sqlite3_stmt *am_stmt;
464
+ int idx = FIX2INT( v_idx );
465
+ const char *n ;
466
+
467
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
468
+ n = sqlite3_column_database_name( am_stmt->stmt, idx ) ;
469
+ return ( n == NULL ? Qnil : rb_str_new2( n ) );
470
+ }
471
+
472
+ /**
473
+ * call-seq:
474
+ * stmt.column_table_name( index ) -> String
475
+ *
476
+ * Return the table name where the data in the ith column of the result set
477
+ * comes from.
478
+ *
479
+ */
480
+ VALUE am_sqlite3_statement_column_table_name(VALUE self, VALUE v_idx)
481
+ {
482
+ am_sqlite3_stmt *am_stmt;
483
+ int idx = FIX2INT( v_idx );
484
+ const char *n ;
485
+
486
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
487
+ n = sqlite3_column_table_name( am_stmt->stmt, idx );
488
+ return ( n == NULL ? Qnil : rb_str_new2( n ) );
489
+ }
490
+
491
+
492
+ /**
493
+ * call-seq:
494
+ * stmt.column_origin_name( index ) -> String
495
+ *
496
+ * Return the column name where the data in the ith column of the result set
497
+ * comes from.
498
+ *
499
+ */
500
+ VALUE am_sqlite3_statement_column_origin_name(VALUE self, VALUE v_idx)
501
+ {
502
+ am_sqlite3_stmt *am_stmt;
503
+ int idx = FIX2INT( v_idx );
504
+ const char *n ;
505
+
506
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
507
+ n = sqlite3_column_origin_name( am_stmt->stmt, idx );
508
+ return ( n == NULL ? Qnil : rb_str_new2( n ) );
509
+ }
510
+
511
+
512
+ /**
513
+ * call-seq:
514
+ * stmt.sql -> String
515
+ *
516
+ * Return a copy of the original string used to create the prepared statement.
517
+ */
518
+ VALUE am_sqlite3_statement_sql(VALUE self)
519
+ {
520
+
521
+ am_sqlite3_stmt *am_stmt;
522
+
523
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
524
+ return rb_str_new2( sqlite3_sql( am_stmt->stmt ) );
525
+
526
+ }
527
+
528
+ /**
529
+ * call-seq:
530
+ * stmt.close -> nil
531
+ *
532
+ * Closes the statement. If there is a problem closing the statement then an
533
+ * error is raised. Closing a statement when there is an existing error is
534
+ * perfectly fine.
535
+ *
536
+ */
537
+ VALUE am_sqlite3_statement_close( VALUE self )
538
+ {
539
+
540
+ am_sqlite3_stmt *am_stmt;
541
+ int rc, existing_errcode;
542
+
543
+ Data_Get_Struct(self, am_sqlite3_stmt, am_stmt);
544
+
545
+ /* check the current error code to see if one exists, we could be
546
+ * closing a statement that has an error, and in that case we do not want to
547
+ * raise an additional error, we want to let the existing error stand
548
+ */
549
+ existing_errcode = sqlite3_errcode( sqlite3_db_handle( am_stmt->stmt ) );
550
+ rc = sqlite3_finalize( am_stmt->stmt );
551
+
552
+ if ( (SQLITE_OK != rc) && (rc != existing_errcode) ) {
553
+ rb_raise(eAS_Error, "Failure to close statement : [SQLITE_ERROR %d] : %s\n",
554
+ rc, sqlite3_errmsg( sqlite3_db_handle( am_stmt->stmt) ));
555
+ }
556
+
557
+ return Qnil;
558
+ }
559
+
560
+ /***********************************************************************
561
+ * Ruby life cycle methods
562
+ ***********************************************************************/
563
+
564
+
565
+ /*
566
+ * garbage collector free method for the am_sqlite3_statement structure
567
+ */
568
+ void am_sqlite3_statement_free(am_sqlite3_stmt* wrapper)
569
+ {
570
+
571
+ if ( Qnil != wrapper->remaining_sql ) {
572
+ rb_gc_unregister_address( &(wrapper->remaining_sql) );
573
+ wrapper->remaining_sql = Qnil;
574
+ }
575
+ free(wrapper);
576
+ return;
577
+ }
578
+
579
+ /*
580
+ * allocate the am_data structure
581
+ */
582
+ VALUE am_sqlite3_statement_alloc(VALUE klass)
583
+ {
584
+ am_sqlite3_stmt *wrapper = ALLOC(am_sqlite3_stmt);
585
+ VALUE obj = (VALUE)NULL;
586
+
587
+ wrapper->remaining_sql = Qnil;
588
+
589
+ obj = Data_Wrap_Struct(klass, NULL, am_sqlite3_statement_free, wrapper);
590
+ return obj;
591
+ }
592
+
593
+ /**
594
+ * Amagalite Database extension
595
+ */
596
+
597
+ void Init_amalgalite3_statement( )
598
+ {
599
+
600
+ VALUE ma = rb_define_module("Amalgalite");
601
+ VALUE mas = rb_define_module_under(ma, "SQLite3");
602
+
603
+ /*
604
+ * Encapsulate the SQLite3 Statement handle in a class
605
+ */
606
+ cAS_Statement = rb_define_class_under( mas, "Statement", rb_cObject );
607
+ rb_define_alloc_func(cAS_Statement, am_sqlite3_statement_alloc);
608
+ rb_define_method(cAS_Statement, "sql", am_sqlite3_statement_sql, 0);
609
+ rb_define_method(cAS_Statement, "close", am_sqlite3_statement_close, 0);
610
+ rb_define_method(cAS_Statement, "step", am_sqlite3_statement_step, 0);
611
+
612
+ rb_define_method(cAS_Statement, "column_count", am_sqlite3_statement_column_count, 0);
613
+ rb_define_method(cAS_Statement, "column_name", am_sqlite3_statement_column_name, 1);
614
+ rb_define_method(cAS_Statement, "column_declared_type", am_sqlite3_statement_column_decltype, 1);
615
+ rb_define_method(cAS_Statement, "column_type", am_sqlite3_statement_column_type, 1);
616
+ rb_define_method(cAS_Statement, "column_text", am_sqlite3_statement_column_text, 1);
617
+ rb_define_method(cAS_Statement, "column_blob", am_sqlite3_statement_column_blob, 1);
618
+ rb_define_method(cAS_Statement, "column_int", am_sqlite3_statement_column_int, 1);
619
+ rb_define_method(cAS_Statement, "column_int64", am_sqlite3_statement_column_int64, 1);
620
+ rb_define_method(cAS_Statement, "column_double", am_sqlite3_statement_column_double, 1);
621
+
622
+ rb_define_method(cAS_Statement, "column_database_name", am_sqlite3_statement_column_database_name, 1);
623
+ rb_define_method(cAS_Statement, "column_table_name", am_sqlite3_statement_column_table_name, 1);
624
+ rb_define_method(cAS_Statement, "column_origin_name", am_sqlite3_statement_column_origin_name, 1);
625
+ rb_define_method(cAS_Statement, "reset!", am_sqlite3_statement_reset, 0);
626
+ rb_define_method(cAS_Statement, "clear_bindings!", am_sqlite3_statement_clear_bindings, 0);
627
+ rb_define_method(cAS_Statement, "parameter_count", am_sqlite3_statement_bind_parameter_count, 0);
628
+ rb_define_method(cAS_Statement, "parameter_index", am_sqlite3_statement_bind_parameter_index, 1);
629
+ rb_define_method(cAS_Statement, "remaining_sql", am_sqlite3_statement_remaining_sql, 0);
630
+ rb_define_method(cAS_Statement, "bind_text", am_sqlite3_statement_bind_text, 2);
631
+ rb_define_method(cAS_Statement, "bind_int", am_sqlite3_statement_bind_int, 2);
632
+ rb_define_method(cAS_Statement, "bind_int64", am_sqlite3_statement_bind_int64, 2);
633
+ rb_define_method(cAS_Statement, "bind_double", am_sqlite3_statement_bind_double, 2);
634
+ rb_define_method(cAS_Statement, "bind_null", am_sqlite3_statement_bind_null, 1);
635
+ rb_define_method(cAS_Statement, "bind_blob", am_sqlite3_statement_bind_blob, 2);
636
+ rb_define_method(cAS_Statement, "bind_zeroblob", am_sqlite3_statement_bind_zeroblob, 2);
637
+ }
638
+
639
+