swift-db-postgres 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.
- data/CHANGELOG +3 -0
 - data/README.md +131 -0
 - data/ext/swift/db/postgres/adapter.c +580 -0
 - data/ext/swift/db/postgres/adapter.h +14 -0
 - data/ext/swift/db/postgres/common.c +59 -0
 - data/ext/swift/db/postgres/common.h +35 -0
 - data/ext/swift/db/postgres/datetime.c +99 -0
 - data/ext/swift/db/postgres/datetime.h +8 -0
 - data/ext/swift/db/postgres/extconf.rb +33 -0
 - data/ext/swift/db/postgres/main.c +28 -0
 - data/ext/swift/db/postgres/result.c +172 -0
 - data/ext/swift/db/postgres/result.h +10 -0
 - data/ext/swift/db/postgres/statement.c +169 -0
 - data/ext/swift/db/postgres/statement.h +9 -0
 - data/ext/swift/db/postgres/typecast.c +112 -0
 - data/ext/swift/db/postgres/typecast.h +24 -0
 - data/lib/swift-db-postgres.rb +1 -0
 - data/lib/swift/db/postgres.rb +1 -0
 - data/test/helper.rb +8 -0
 - data/test/test_adapter.rb +106 -0
 - data/test/test_async.rb +34 -0
 - data/test/test_encoding.rb +30 -0
 - data/test/test_ssl.rb +15 -0
 - metadata +87 -0
 
| 
         @@ -0,0 +1,169 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // vim:ts=4:sts=4:sw=4:expandtab
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            // (c) Bharanee Rathna 2012
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #include "statement.h"
         
     | 
| 
      
 6 
     | 
    
         
            +
            #include "adapter.h"
         
     | 
| 
      
 7 
     | 
    
         
            +
            #include "typecast.h"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            /* declaration */
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            VALUE cDPS;
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            VALUE    db_postgres_result_allocate(VALUE);
         
     | 
| 
      
 14 
     | 
    
         
            +
            VALUE    db_postgres_result_load(VALUE, PGresult*);
         
     | 
| 
      
 15 
     | 
    
         
            +
            Adapter* db_postgres_adapter_handle_safe(VALUE);
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            typedef struct Statement {
         
     | 
| 
      
 18 
     | 
    
         
            +
                char id[64];
         
     | 
| 
      
 19 
     | 
    
         
            +
                VALUE adapter;
         
     | 
| 
      
 20 
     | 
    
         
            +
            } Statement;
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            /* definition */
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            Statement* db_postgres_statement_handle(VALUE self) {
         
     | 
| 
      
 25 
     | 
    
         
            +
                Statement *s;
         
     | 
| 
      
 26 
     | 
    
         
            +
                Data_Get_Struct(self, Statement, s);
         
     | 
| 
      
 27 
     | 
    
         
            +
                if (!s)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    rb_raise(eSwiftRuntimeError, "Invalid postgres statement");
         
     | 
| 
      
 29 
     | 
    
         
            +
                return s;
         
     | 
| 
      
 30 
     | 
    
         
            +
            }
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            Statement* db_postgres_statement_handle_safe(VALUE self) {
         
     | 
| 
      
 33 
     | 
    
         
            +
                Statement *s = db_postgres_statement_handle(self);
         
     | 
| 
      
 34 
     | 
    
         
            +
                if (!s->adapter)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    rb_raise(eSwiftRuntimeError, "Invalid postgres statement: no associated adapter");
         
     | 
| 
      
 36 
     | 
    
         
            +
                return s;
         
     | 
| 
      
 37 
     | 
    
         
            +
            }
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            void db_postgres_statement_mark(Statement *s) {
         
     | 
| 
      
 40 
     | 
    
         
            +
                if (s && s->adapter)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    rb_gc_mark_maybe(s->adapter);
         
     | 
| 
      
 42 
     | 
    
         
            +
            }
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            VALUE db_postgres_statement_deallocate(Statement *s) {
         
     | 
| 
      
 45 
     | 
    
         
            +
                if (s)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    free(s);
         
     | 
| 
      
 47 
     | 
    
         
            +
            }
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            VALUE db_postgres_statement_allocate(VALUE klass) {
         
     | 
| 
      
 50 
     | 
    
         
            +
                Statement *s = (Statement*)malloc(sizeof(Statement));
         
     | 
| 
      
 51 
     | 
    
         
            +
                memset(s, 0, sizeof(Statement));
         
     | 
| 
      
 52 
     | 
    
         
            +
                return Data_Wrap_Struct(klass, db_postgres_statement_mark, db_postgres_statement_deallocate, s);
         
     | 
| 
      
 53 
     | 
    
         
            +
            }
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            VALUE db_postgres_statement_initialize(VALUE self, VALUE adapter, VALUE sql) {
         
     | 
| 
      
 56 
     | 
    
         
            +
                PGresult *result;
         
     | 
| 
      
 57 
     | 
    
         
            +
                PGconn *connection;
         
     | 
| 
      
 58 
     | 
    
         
            +
                Statement *s = db_postgres_statement_handle(self);
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                snprintf(s->id, 64, "s%s", CSTRING(rb_uuid_string()));
         
     | 
| 
      
 61 
     | 
    
         
            +
                s->adapter = adapter;
         
     | 
| 
      
 62 
     | 
    
         
            +
                rb_gc_mark(s->adapter);
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                connection = db_postgres_adapter_handle_safe(adapter)->connection;
         
     | 
| 
      
 65 
     | 
    
         
            +
                result     = PQprepare(connection, s->id, CSTRING(db_postgres_normalized_sql(sql)), 0, 0);
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                db_postgres_check_result(result);
         
     | 
| 
      
 68 
     | 
    
         
            +
                PQclear(result);
         
     | 
| 
      
 69 
     | 
    
         
            +
                return self;
         
     | 
| 
      
 70 
     | 
    
         
            +
            }
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            VALUE db_postgres_statement_release(VALUE self) {
         
     | 
| 
      
 73 
     | 
    
         
            +
                char command[128];
         
     | 
| 
      
 74 
     | 
    
         
            +
                PGresult *result;
         
     | 
| 
      
 75 
     | 
    
         
            +
                PGconn *connection;
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                Statement *s = db_postgres_statement_handle_safe(self);
         
     | 
| 
      
 78 
     | 
    
         
            +
                connection   = db_postgres_adapter_handle_safe(s->adapter)->connection;
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                if (connection && PQstatus(connection) == CONNECTION_OK) {
         
     | 
| 
      
 81 
     | 
    
         
            +
                    snprintf(command, 128, "deallocate %s", s->id);
         
     | 
| 
      
 82 
     | 
    
         
            +
                    result = PQexec(connection, command);
         
     | 
| 
      
 83 
     | 
    
         
            +
                    db_postgres_check_result(result);
         
     | 
| 
      
 84 
     | 
    
         
            +
                    PQclear(result);
         
     | 
| 
      
 85 
     | 
    
         
            +
                    return Qtrue;
         
     | 
| 
      
 86 
     | 
    
         
            +
                }
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                return Qfalse;
         
     | 
| 
      
 89 
     | 
    
         
            +
            }
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            VALUE nogvl_pq_exec_prepared(void *ptr) {
         
     | 
| 
      
 92 
     | 
    
         
            +
                Query *q = (Query *)ptr;
         
     | 
| 
      
 93 
     | 
    
         
            +
                return (VALUE)PQexecPrepared(q->connection, q->command, q->n_args, (const char * const *)q->data, q->size, q->format, 0);
         
     | 
| 
      
 94 
     | 
    
         
            +
            }
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            VALUE db_postgres_statement_execute(int argc, VALUE *argv, VALUE self) {
         
     | 
| 
      
 97 
     | 
    
         
            +
                PGresult *result;
         
     | 
| 
      
 98 
     | 
    
         
            +
                PGconn *connection;
         
     | 
| 
      
 99 
     | 
    
         
            +
                char **bind_args_data = 0;
         
     | 
| 
      
 100 
     | 
    
         
            +
                int n, *bind_args_size = 0, *bind_args_fmt = 0;
         
     | 
| 
      
 101 
     | 
    
         
            +
                VALUE bind, data;
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                Statement *s = db_postgres_statement_handle_safe(self);
         
     | 
| 
      
 104 
     | 
    
         
            +
                connection   = db_postgres_adapter_handle_safe(s->adapter)->connection;
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                rb_scan_args(argc, argv, "00*", &bind);
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                if (RARRAY_LEN(bind) > 0) {
         
     | 
| 
      
 109 
     | 
    
         
            +
                    bind_args_size = (int   *) malloc(sizeof(int)    * RARRAY_LEN(bind));
         
     | 
| 
      
 110 
     | 
    
         
            +
                    bind_args_fmt  = (int   *) malloc(sizeof(int)    * RARRAY_LEN(bind));
         
     | 
| 
      
 111 
     | 
    
         
            +
                    bind_args_data = (char **) malloc(sizeof(char *) * RARRAY_LEN(bind));
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                    for (n = 0; n < RARRAY_LEN(bind); n++) {
         
     | 
| 
      
 114 
     | 
    
         
            +
                        data = rb_ary_entry(bind, n);
         
     | 
| 
      
 115 
     | 
    
         
            +
                        if (NIL_P(data)) {
         
     | 
| 
      
 116 
     | 
    
         
            +
                            bind_args_size[n] = 0;
         
     | 
| 
      
 117 
     | 
    
         
            +
                            bind_args_data[n] = 0;
         
     | 
| 
      
 118 
     | 
    
         
            +
                            bind_args_fmt[n]  = 0;
         
     | 
| 
      
 119 
     | 
    
         
            +
                        }
         
     | 
| 
      
 120 
     | 
    
         
            +
                        else {
         
     | 
| 
      
 121 
     | 
    
         
            +
                            if (rb_obj_is_kind_of(data, rb_cIO) || rb_obj_is_kind_of(data, cStringIO))
         
     | 
| 
      
 122 
     | 
    
         
            +
                                bind_args_fmt[n] = 1;
         
     | 
| 
      
 123 
     | 
    
         
            +
                            else
         
     | 
| 
      
 124 
     | 
    
         
            +
                                bind_args_fmt[n] = 0;
         
     | 
| 
      
 125 
     | 
    
         
            +
                            data = typecast_to_string(data);
         
     | 
| 
      
 126 
     | 
    
         
            +
                            bind_args_size[n] = RSTRING_LEN(data);
         
     | 
| 
      
 127 
     | 
    
         
            +
                            bind_args_data[n] = RSTRING_PTR(data);
         
     | 
| 
      
 128 
     | 
    
         
            +
                        }
         
     | 
| 
      
 129 
     | 
    
         
            +
                    }
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                    Query q = {
         
     | 
| 
      
 132 
     | 
    
         
            +
                        .connection = connection,
         
     | 
| 
      
 133 
     | 
    
         
            +
                        .command    = s->id,
         
     | 
| 
      
 134 
     | 
    
         
            +
                        .n_args     = RARRAY_LEN(bind),
         
     | 
| 
      
 135 
     | 
    
         
            +
                        .data       = bind_args_data,
         
     | 
| 
      
 136 
     | 
    
         
            +
                        .size       = bind_args_size,
         
     | 
| 
      
 137 
     | 
    
         
            +
                        .format     = bind_args_fmt
         
     | 
| 
      
 138 
     | 
    
         
            +
                    };
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                    result = (PGresult *)rb_thread_blocking_region(nogvl_pq_exec_prepared, &q, RUBY_UBF_IO, 0);
         
     | 
| 
      
 141 
     | 
    
         
            +
                    free(bind_args_fmt);
         
     | 
| 
      
 142 
     | 
    
         
            +
                    free(bind_args_size);
         
     | 
| 
      
 143 
     | 
    
         
            +
                    free(bind_args_data);
         
     | 
| 
      
 144 
     | 
    
         
            +
                }
         
     | 
| 
      
 145 
     | 
    
         
            +
                else {
         
     | 
| 
      
 146 
     | 
    
         
            +
                    Query q = {
         
     | 
| 
      
 147 
     | 
    
         
            +
                        .connection = connection,
         
     | 
| 
      
 148 
     | 
    
         
            +
                        .command    = s->id,
         
     | 
| 
      
 149 
     | 
    
         
            +
                        .n_args     = 0,
         
     | 
| 
      
 150 
     | 
    
         
            +
                        .data       = 0,
         
     | 
| 
      
 151 
     | 
    
         
            +
                        .size       = 0,
         
     | 
| 
      
 152 
     | 
    
         
            +
                        .format     = 0
         
     | 
| 
      
 153 
     | 
    
         
            +
                    };
         
     | 
| 
      
 154 
     | 
    
         
            +
                    result = (PGresult *)rb_thread_blocking_region(nogvl_pq_exec_prepared, &q, RUBY_UBF_IO, 0);
         
     | 
| 
      
 155 
     | 
    
         
            +
                }
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                db_postgres_check_result(result);
         
     | 
| 
      
 158 
     | 
    
         
            +
                return db_postgres_result_load(db_postgres_result_allocate(cDPR), result);
         
     | 
| 
      
 159 
     | 
    
         
            +
            }
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
            void init_swift_db_postgres_statement() {
         
     | 
| 
      
 162 
     | 
    
         
            +
                cDPS = rb_define_class_under(cDPA, "Statement", rb_cObject);
         
     | 
| 
      
 163 
     | 
    
         
            +
                rb_define_alloc_func(cDPS, db_postgres_statement_allocate);
         
     | 
| 
      
 164 
     | 
    
         
            +
                rb_define_method(cDPS, "initialize", db_postgres_statement_initialize, 2);
         
     | 
| 
      
 165 
     | 
    
         
            +
                rb_define_method(cDPS, "execute",    db_postgres_statement_execute,   -1);
         
     | 
| 
      
 166 
     | 
    
         
            +
                rb_define_method(cDPS, "release",    db_postgres_statement_release,    0);
         
     | 
| 
      
 167 
     | 
    
         
            +
            }
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,112 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // vim:ts=4:sts=4:sw=4:expandtab
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            // (c) Bharanee Rathna 2012
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #include "common.h"
         
     | 
| 
      
 6 
     | 
    
         
            +
            #include "typecast.h"
         
     | 
| 
      
 7 
     | 
    
         
            +
            #include "datetime.h"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            #define date_parse(klass, data,len) rb_funcall(datetime_parse(klass, data, len), fto_date, 0)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            ID fnew, fto_date, fstrftime;
         
     | 
| 
      
 12 
     | 
    
         
            +
            VALUE cBigDecimal, cStringIO;
         
     | 
| 
      
 13 
     | 
    
         
            +
            VALUE dtformat;
         
     | 
| 
      
 14 
     | 
    
         
            +
            VALUE cDateTime;
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            VALUE typecast_string(const char *data, size_t n) {
         
     | 
| 
      
 17 
     | 
    
         
            +
                return rb_enc_str_new(data, n, rb_utf8_encoding());
         
     | 
| 
      
 18 
     | 
    
         
            +
            }
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            VALUE typecast_detect(const char *data, size_t size, int type) {
         
     | 
| 
      
 21 
     | 
    
         
            +
                VALUE value;
         
     | 
| 
      
 22 
     | 
    
         
            +
                char *bytea;
         
     | 
| 
      
 23 
     | 
    
         
            +
                size_t bytea_len;
         
     | 
| 
      
 24 
     | 
    
         
            +
                switch (type) {
         
     | 
| 
      
 25 
     | 
    
         
            +
                    case SWIFT_TYPE_INT:
         
     | 
| 
      
 26 
     | 
    
         
            +
                        return rb_cstr2inum(data, 10);
         
     | 
| 
      
 27 
     | 
    
         
            +
                    case SWIFT_TYPE_FLOAT:
         
     | 
| 
      
 28 
     | 
    
         
            +
                        return rb_float_new(atof(data));
         
     | 
| 
      
 29 
     | 
    
         
            +
                    case SWIFT_TYPE_NUMERIC:
         
     | 
| 
      
 30 
     | 
    
         
            +
                        return rb_funcall(cBigDecimal, fnew, 1, rb_str_new(data, size));
         
     | 
| 
      
 31 
     | 
    
         
            +
                    case SWIFT_TYPE_BOOLEAN:
         
     | 
| 
      
 32 
     | 
    
         
            +
                        return (data && (data[0] =='t' || data[0] == '1')) ? Qtrue : Qfalse;
         
     | 
| 
      
 33 
     | 
    
         
            +
                    case SWIFT_TYPE_BLOB:
         
     | 
| 
      
 34 
     | 
    
         
            +
                        bytea = PQunescapeBytea(data, &bytea_len);
         
     | 
| 
      
 35 
     | 
    
         
            +
                        value = rb_str_new(bytea, bytea_len);
         
     | 
| 
      
 36 
     | 
    
         
            +
                        PQfreemem(bytea);
         
     | 
| 
      
 37 
     | 
    
         
            +
                        return rb_funcall(cStringIO, fnew, 1, value);
         
     | 
| 
      
 38 
     | 
    
         
            +
                    case SWIFT_TYPE_TIMESTAMP:
         
     | 
| 
      
 39 
     | 
    
         
            +
                        return datetime_parse(cSwiftDateTime, data, size);
         
     | 
| 
      
 40 
     | 
    
         
            +
                    case SWIFT_TYPE_DATE:
         
     | 
| 
      
 41 
     | 
    
         
            +
                        return date_parse(cSwiftDateTime, data, size);
         
     | 
| 
      
 42 
     | 
    
         
            +
                    default:
         
     | 
| 
      
 43 
     | 
    
         
            +
                        return rb_enc_str_new(data, size, rb_utf8_encoding());
         
     | 
| 
      
 44 
     | 
    
         
            +
                }
         
     | 
| 
      
 45 
     | 
    
         
            +
            }
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            #define TO_UTF8(value) rb_str_encode(value, rb_str_new2("UTF-8"), 0, Qnil)
         
     | 
| 
      
 48 
     | 
    
         
            +
            #define UTF8_STRING(value) strcmp(rb_enc_get(value)->name, "UTF-8") ? TO_UTF8(value) : value
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            VALUE typecast_to_string(VALUE value) {
         
     | 
| 
      
 51 
     | 
    
         
            +
                switch (TYPE(value)) {
         
     | 
| 
      
 52 
     | 
    
         
            +
                    case T_STRING:
         
     | 
| 
      
 53 
     | 
    
         
            +
                        return UTF8_STRING(value);
         
     | 
| 
      
 54 
     | 
    
         
            +
                    case T_TRUE:
         
     | 
| 
      
 55 
     | 
    
         
            +
                        return rb_str_new2("1");
         
     | 
| 
      
 56 
     | 
    
         
            +
                    case T_FALSE:
         
     | 
| 
      
 57 
     | 
    
         
            +
                        return rb_str_new2("0");
         
     | 
| 
      
 58 
     | 
    
         
            +
                    default:
         
     | 
| 
      
 59 
     | 
    
         
            +
                        if (rb_obj_is_kind_of(value, rb_cTime) || rb_obj_is_kind_of(value, cDateTime))
         
     | 
| 
      
 60 
     | 
    
         
            +
                            return rb_funcall(value, fstrftime, 1, dtformat);
         
     | 
| 
      
 61 
     | 
    
         
            +
                        else if (rb_obj_is_kind_of(value, rb_cIO) || rb_obj_is_kind_of(value, cStringIO))
         
     | 
| 
      
 62 
     | 
    
         
            +
                            return rb_funcall(value, rb_intern("read"), 0);
         
     | 
| 
      
 63 
     | 
    
         
            +
                        else
         
     | 
| 
      
 64 
     | 
    
         
            +
                            return UTF8_STRING(rb_funcall(value, rb_intern("to_s"), 0));
         
     | 
| 
      
 65 
     | 
    
         
            +
                }
         
     | 
| 
      
 66 
     | 
    
         
            +
            }
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            VALUE typecast_description(VALUE list) {
         
     | 
| 
      
 69 
     | 
    
         
            +
                int n;
         
     | 
| 
      
 70 
     | 
    
         
            +
                VALUE types = rb_ary_new();
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                for (n = 0; n < RARRAY_LEN(list); n++) {
         
     | 
| 
      
 73 
     | 
    
         
            +
                    switch (NUM2INT(rb_ary_entry(list, n))) {
         
     | 
| 
      
 74 
     | 
    
         
            +
                        case SWIFT_TYPE_INT:
         
     | 
| 
      
 75 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("integer")); break;
         
     | 
| 
      
 76 
     | 
    
         
            +
                        case SWIFT_TYPE_NUMERIC:
         
     | 
| 
      
 77 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("numeric")); break;
         
     | 
| 
      
 78 
     | 
    
         
            +
                        case SWIFT_TYPE_FLOAT:
         
     | 
| 
      
 79 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("float")); break;
         
     | 
| 
      
 80 
     | 
    
         
            +
                        case SWIFT_TYPE_BLOB:
         
     | 
| 
      
 81 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("blob")); break;
         
     | 
| 
      
 82 
     | 
    
         
            +
                        case SWIFT_TYPE_DATE:
         
     | 
| 
      
 83 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("date")); break;
         
     | 
| 
      
 84 
     | 
    
         
            +
                        case SWIFT_TYPE_TIME:
         
     | 
| 
      
 85 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("time")); break;
         
     | 
| 
      
 86 
     | 
    
         
            +
                        case SWIFT_TYPE_TIMESTAMP:
         
     | 
| 
      
 87 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("timestamp")); break;
         
     | 
| 
      
 88 
     | 
    
         
            +
                        case SWIFT_TYPE_BOOLEAN:
         
     | 
| 
      
 89 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("boolean")); break;
         
     | 
| 
      
 90 
     | 
    
         
            +
                        default:
         
     | 
| 
      
 91 
     | 
    
         
            +
                            rb_ary_push(types, rb_str_new2("text"));
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
                    }
         
     | 
| 
      
 94 
     | 
    
         
            +
                }
         
     | 
| 
      
 95 
     | 
    
         
            +
                return types;
         
     | 
| 
      
 96 
     | 
    
         
            +
            }
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
            void init_swift_db_postgres_typecast() {
         
     | 
| 
      
 99 
     | 
    
         
            +
                rb_require("bigdecimal");
         
     | 
| 
      
 100 
     | 
    
         
            +
                rb_require("stringio");
         
     | 
| 
      
 101 
     | 
    
         
            +
                rb_require("date");
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                cStringIO   = CONST_GET(rb_mKernel, "StringIO");
         
     | 
| 
      
 104 
     | 
    
         
            +
                cBigDecimal = CONST_GET(rb_mKernel, "BigDecimal");
         
     | 
| 
      
 105 
     | 
    
         
            +
                cDateTime   = CONST_GET(rb_mKernel, "DateTime");
         
     | 
| 
      
 106 
     | 
    
         
            +
                fnew        = rb_intern("new");
         
     | 
| 
      
 107 
     | 
    
         
            +
                fto_date    = rb_intern("to_date");
         
     | 
| 
      
 108 
     | 
    
         
            +
                fstrftime   = rb_intern("strftime");
         
     | 
| 
      
 109 
     | 
    
         
            +
                dtformat    = rb_str_new2("%F %T.%N %z");
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                rb_global_variable(&dtformat);
         
     | 
| 
      
 112 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            // vim:ts=4:sts=4:sw=4:expandtab
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            // (c) Bharanee Rathna 2012
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #pragma once
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            #include "common.h"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            #define SWIFT_TYPE_INT       0
         
     | 
| 
      
 10 
     | 
    
         
            +
            #define SWIFT_TYPE_FLOAT     1
         
     | 
| 
      
 11 
     | 
    
         
            +
            #define SWIFT_TYPE_NUMERIC   2
         
     | 
| 
      
 12 
     | 
    
         
            +
            #define SWIFT_TYPE_BOOLEAN   3
         
     | 
| 
      
 13 
     | 
    
         
            +
            #define SWIFT_TYPE_DATE      4
         
     | 
| 
      
 14 
     | 
    
         
            +
            #define SWIFT_TYPE_TIME      5
         
     | 
| 
      
 15 
     | 
    
         
            +
            #define SWIFT_TYPE_TIMESTAMP 6
         
     | 
| 
      
 16 
     | 
    
         
            +
            #define SWIFT_TYPE_TEXT      7
         
     | 
| 
      
 17 
     | 
    
         
            +
            #define SWIFT_TYPE_BLOB      8
         
     | 
| 
      
 18 
     | 
    
         
            +
            #define SWIFT_TYPE_UNKNOWN   9
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            DLL_PRIVATE VALUE typecast_to_string(VALUE);
         
     | 
| 
      
 21 
     | 
    
         
            +
            DLL_PRIVATE VALUE typecast_string(const char *, size_t);
         
     | 
| 
      
 22 
     | 
    
         
            +
            DLL_PRIVATE VALUE typecast_detect(const char *, size_t, int);
         
     | 
| 
      
 23 
     | 
    
         
            +
            DLL_PRIVATE VALUE typecast_description(VALUE list);
         
     | 
| 
      
 24 
     | 
    
         
            +
            DLL_PRIVATE void  init_swift_db_postgres_typecast();
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'swift/db/postgres'
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'swift/db/postgres/swift_db_postgres_ext'
         
     | 
    
        data/test/helper.rb
    ADDED
    
    
| 
         @@ -0,0 +1,106 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
             describe 'postgres adapter' do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it 'should initialize' do
         
     | 
| 
      
 5 
     | 
    
         
            +
                assert db
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it 'should execute sql' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                assert db.execute("select * from pg_tables")
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              it 'should expect the correct number of bind args' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                assert_raises(Swift::ArgumentError) { db.execute("select * from pg_tables where tablename = ?", 1, 2) }
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it 'should return result on #execute' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                now = Time.now
         
     | 
| 
      
 18 
     | 
    
         
            +
                assert db.execute('drop table if exists users')
         
     | 
| 
      
 19 
     | 
    
         
            +
                assert db.execute('create table users (id serial primary key, name text, age integer, created_at timestamp with time zone)')
         
     | 
| 
      
 20 
     | 
    
         
            +
                assert db.execute('insert into users(name, age, created_at) values(?, ?, ?)', 'test', nil, now)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                result = db.execute('select * from users')
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                assert_equal 1, result.selected_rows
         
     | 
| 
      
 25 
     | 
    
         
            +
                assert_equal 0, result.affected_rows
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_equal %w(id name age created_at).map(&:to_sym), result.fields
         
     | 
| 
      
 27 
     | 
    
         
            +
                assert_equal %w(integer text integer timestamp), result.types
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                row = result.first
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_equal 1,      row[:id]
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal 'test', row[:name]
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert_equal nil,    row[:age]
         
     | 
| 
      
 33 
     | 
    
         
            +
                assert_equal now.to_f.round(3), row[:created_at].to_time.to_f.round(3) # millisecs resolution on postgres
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                result = db.execute('delete from users where id = 0')
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_equal 0, result.selected_rows
         
     | 
| 
      
 37 
     | 
    
         
            +
                assert_equal 0, result.affected_rows
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                assert_equal 1, db.execute('select count(*) as count from users').first[:count]
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                result = db.execute('delete from users')
         
     | 
| 
      
 42 
     | 
    
         
            +
                assert_equal 0, result.selected_rows
         
     | 
| 
      
 43 
     | 
    
         
            +
                assert_equal 1, result.affected_rows
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                # empty result should have field & type information
         
     | 
| 
      
 46 
     | 
    
         
            +
                result = db.execute('select * from users')
         
     | 
| 
      
 47 
     | 
    
         
            +
                assert_equal %w(id name age created_at).map(&:to_sym), result.fields
         
     | 
| 
      
 48 
     | 
    
         
            +
                assert_equal %w(integer text integer timestamp), result.types
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              it 'should close handle' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                assert !db.closed?
         
     | 
| 
      
 53 
     | 
    
         
            +
                assert db.close
         
     | 
| 
      
 54 
     | 
    
         
            +
                assert db.closed?
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                assert_raises(Swift::ConnectionError) { db.execute("select * from users") }
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              it 'should prepare & release statement' do
         
     | 
| 
      
 60 
     | 
    
         
            +
                assert db.execute('drop table if exists users')
         
     | 
| 
      
 61 
     | 
    
         
            +
                assert db.execute("create table users(id serial primary key, name text)")
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert db.execute("insert into users (name) values (?)", "test")
         
     | 
| 
      
 63 
     | 
    
         
            +
                assert s = db.prepare("select * from users where id > ?")
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                assert_equal 1, s.execute(0).selected_rows
         
     | 
| 
      
 66 
     | 
    
         
            +
                assert_equal 0, s.execute(1).selected_rows
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                assert s.release
         
     | 
| 
      
 69 
     | 
    
         
            +
                assert_raises(Swift::RuntimeError) { s.execute(1) }
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              it 'should escape whatever' do
         
     | 
| 
      
 73 
     | 
    
         
            +
                assert_equal "foo''bar", db.escape("foo'bar")
         
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
              it 'should support #write and #read' do
         
     | 
| 
      
 77 
     | 
    
         
            +
                assert db.execute('drop table if exists users')
         
     | 
| 
      
 78 
     | 
    
         
            +
                assert db.execute("create table users(id serial primary key, name text)")
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                assert_equal 3, db.write('users', %w(name), "foo\nbar\nbaz\n").affected_rows
         
     | 
| 
      
 81 
     | 
    
         
            +
                assert_equal 3, db.execute('select count(*) as count from users').first[:count]
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                assert db.execute('copy users(name) from stdin')
         
     | 
| 
      
 84 
     | 
    
         
            +
                assert_equal 3, db.write("foo\nbar\nbaz\n").affected_rows
         
     | 
| 
      
 85 
     | 
    
         
            +
                assert_equal 6, db.execute('select count(*) as count from users').first[:count]
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                assert_equal 3, db.write('users', StringIO.new("7\tfoo\n8\tbar\n9\tbaz\n")).affected_rows
         
     | 
| 
      
 88 
     | 
    
         
            +
                assert_equal 9, db.execute('select count(*) as count from users').first[:count]
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                io = StringIO.new
         
     | 
| 
      
 91 
     | 
    
         
            +
                db.execute('copy (select * from users order by id limit 1) to stdout with csv')
         
     | 
| 
      
 92 
     | 
    
         
            +
                assert_equal 1, db.read(io).affected_rows
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                assert_match %r{1,foo\n}, io.tap(&:rewind).read
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                rows = []
         
     | 
| 
      
 97 
     | 
    
         
            +
                db.read('users') {|row| rows << row}
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                expect = (%w(foo bar baz)*3).zip(1..9).map {|r| r.reverse.join("\t") + "\n"}
         
     | 
| 
      
 100 
     | 
    
         
            +
                assert_equal expect, rows
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                assert_raises(Swift::RuntimeError) { db.write("foo") }
         
     | 
| 
      
 103 
     | 
    
         
            +
                assert_raises(Swift::RuntimeError) { db.write("users", "bar") }
         
     | 
| 
      
 104 
     | 
    
         
            +
                assert_raises(Swift::RuntimeError) { db.write("users", %w(name), "bar") }
         
     | 
| 
      
 105 
     | 
    
         
            +
              end
         
     | 
| 
      
 106 
     | 
    
         
            +
            end
         
     |