ext/pg.h in pg-0.18.0.pre20140820094244 vs ext/pg.h in pg-0.18.0.pre20141017155815

- old
+ new

@@ -22,23 +22,42 @@ #endif #if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H # include "ruby/encoding.h" # define M17N_SUPPORTED -# define ASSOCIATE_INDEX( obj, index_holder ) rb_enc_associate_index((obj), pg_enc_get_index((index_holder))) # ifdef HAVE_RB_ENCDB_ALIAS extern int rb_encdb_alias(const char *, const char *); # define ENC_ALIAS(name, orig) rb_encdb_alias((name), (orig)) # elif HAVE_RB_ENC_ALIAS extern int rb_enc_alias(const char *, const char *); # define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig)) # else extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */ # define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig)) # endif + + +# if !defined(ENCODING_SET_INLINED) +/* Rubinius doesn't define ENCODING_SET_INLINED, so we fall back to the more + * portable version. + */ +# define PG_ENCODING_SET_NOCHECK(obj,i) \ + do { \ + rb_enc_set_index((obj), (i)); \ + } while(0) +# else +# define PG_ENCODING_SET_NOCHECK(obj,i) \ + do { \ + if ((i) < ENCODING_INLINE_MAX) \ + ENCODING_SET_INLINED((obj), (i)); \ + else \ + rb_enc_set_index((obj), (i)); \ + } while(0) +# endif + #else -# define ASSOCIATE_INDEX( obj, index_holder ) /* nothing */ +# define PG_ENCODING_SET_NOCHECK(obj,i) /* nothing */ #endif #if RUBY_VM != 1 # define RUBY_18_COMPAT #endif @@ -64,10 +83,15 @@ # include "rubyio.h" #else # include "ruby/io.h" #endif +#ifdef RUBINIUS + /* Workaround for wrong FIXNUM_MAX definition */ + typedef intptr_t native_int; +#endif + #ifndef timeradd #define timeradd(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ @@ -95,14 +119,105 @@ #include "libpq/libpq-fs.h" /* large-object interface */ #include "pg_config_manual.h" #if defined(_WIN32) # include <fcntl.h> -__declspec(dllexport) typedef long suseconds_t; #endif +/* The data behind each PG::Connection object */ +typedef struct { + PGconn *pgconn; + + /* Cached IO object for the socket descriptor */ + VALUE socket_io; + /* Proc object that receives notices as PG::Result objects */ + VALUE notice_receiver; + /* Proc object that receives notices as String objects */ + VALUE notice_processor; + /* Kind of PG::TypeMap object for casting query params */ + VALUE type_map_for_queries; + /* Kind of PG::TypeMap object for casting result values */ + VALUE type_map_for_results; + /* IO object internally used for the trace stream */ + VALUE trace_stream; + /* Cached Encoding object */ + VALUE external_encoding; + /* Kind of PG::Coder object for casting ruby values to COPY rows */ + VALUE encoder_for_put_copy_data; + /* Kind of PG::Coder object for casting COPY rows to ruby values */ + VALUE decoder_for_get_copy_data; + +} t_pg_connection; + +typedef struct pg_coder t_pg_coder; +typedef struct pg_typemap t_typemap; + +/* The data behind each PG::Result object */ +typedef struct { + PGresult *pgresult; + + /* The connection object used to build this result */ + VALUE connection; + + /* The TypeMap used to type cast result values */ + VALUE typemap; + + /* Pointer to the typemap object data. This is assumed to be + * always valid. + */ + t_typemap *p_typemap; + + /* 0 = PGresult is cleared by PG::Result#clear or by the GC + * 1 = PGresult is cleared internally by libpq + */ + int autoclear; +} t_pg_result; + + +typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *); +typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, char *, int, int, int, int); +typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE); +typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE); +typedef int (* t_pg_fit_to_copy_get)(VALUE); +typedef VALUE (* t_pg_typecast_result)(VALUE, int, int); +typedef t_pg_coder *(* t_pg_typecast_query_param)(VALUE, VALUE, int); +typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int ); + +struct pg_coder { + t_pg_coder_enc_func enc_func; + t_pg_coder_dec_func dec_func; + VALUE coder_obj; + Oid oid; + int format; +}; + +typedef struct { + t_pg_coder comp; + t_pg_coder *elem; + int needs_quotation; + char delimiter; +} t_pg_composite_coder; + +struct pg_typemap { + t_pg_fit_to_result fit_to_result; + t_pg_fit_to_query fit_to_query; + t_pg_fit_to_copy_get fit_to_copy_get; + t_pg_typecast_result typecast_result_value; + t_pg_typecast_query_param typecast_query_param; + t_pg_typecast_copy_get typecast_copy_get; +}; + +typedef struct { + t_typemap typemap; + int nfields; + struct pg_tmbc_converter { + t_pg_coder *cconv; + } convs[0]; +} t_tmbc; + + #include "gvl_wrappers.h" /*************************************************************************** * Globals **************************************************************************/ @@ -114,11 +229,27 @@ extern VALUE rb_eConnectionBad; extern VALUE rb_mPGconstants; extern VALUE rb_cPGconn; extern VALUE rb_cPGresult; extern VALUE rb_hErrors; +extern VALUE rb_cTypeMap; +extern VALUE rb_cTypeMapAllStrings; +extern VALUE rb_cPG_Coder; +extern VALUE rb_cPG_SimpleEncoder; +extern VALUE rb_cPG_SimpleDecoder; +extern VALUE rb_cPG_CompositeEncoder; +extern VALUE rb_cPG_CompositeDecoder; +extern VALUE rb_cPG_CopyCoder; +extern VALUE rb_cPG_CopyEncoder; +extern VALUE rb_cPG_CopyDecoder; +extern VALUE rb_mPG_TextEncoder; +extern VALUE rb_mPG_TextDecoder; +extern VALUE rb_mPG_BinaryEncoder; +extern VALUE rb_mPG_BinaryDecoder; +extern const t_typemap pg_tmbc_default_typemap; +extern VALUE pg_default_typemap; /*************************************************************************** * MACROS **************************************************************************/ @@ -132,22 +263,79 @@ void Init_pg_ext _(( void )); void init_pg_connection _(( void )); void init_pg_result _(( void )); void init_pg_errors _(( void )); -VALUE lookup_error_class _(( const char *sqlstate )); +void init_pg_type_map _(( void )); +void init_pg_type_map_all_strings _(( void )); +void init_pg_type_map_by_column _(( void )); +void init_pg_type_map_by_mri_type _(( void )); +void init_pg_type_map_by_oid _(( void )); +void init_pg_coder _(( void )); +void init_pg_copycoder _(( void )); +void init_pg_text_encoder _(( void )); +void init_pg_text_decoder _(( void )); +void init_pg_binary_encoder _(( void )); +void init_pg_binary_decoder _(( void )); +VALUE lookup_error_class _(( const char * )); +VALUE pg_bin_dec_bytea _(( t_pg_coder*, char *, int, int, int, int )); +VALUE pg_text_dec_string _(( t_pg_coder*, char *, int, int, int, int )); +int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *)); +t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* )); +t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int )); +void pg_define_coder _(( const char *, void *, VALUE, VALUE )); +VALUE pg_obj_to_i _(( VALUE )); +VALUE pg_tmbc_allocate _(( void )); +void pg_coder_init_encoder _(( VALUE )); +void pg_coder_init_decoder _(( VALUE )); +char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** )); -PGconn *pg_get_pgconn _(( VALUE )); +#define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \ + do { \ + if( (curr_ptr) + (expand_len) >= (end_ptr) ) \ + (curr_ptr) = pg_rb_str_ensure_capa( (str), (expand_len), (curr_ptr), &(end_ptr) ); \ + } while(0); +#define PG_RB_STR_NEW( str, curr_ptr, end_ptr ) ( \ + (str) = rb_str_new( NULL, 0 ), \ + (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \ + ) + +#define PG_RB_TAINTED_STR_NEW( str, curr_ptr, end_ptr ) ( \ + (str) = rb_tainted_str_new( NULL, 0 ), \ + (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \ + ) + +VALUE pg_typemap_fit_to_result _(( VALUE, VALUE )); +VALUE pg_typemap_fit_to_query _(( VALUE, VALUE )); +int pg_typemap_fit_to_copy_get _(( VALUE )); +VALUE pg_typemap_result_value _(( VALUE, int, int )); +t_pg_coder *pg_typemap_typecast_query_param _(( VALUE, VALUE, int )); +VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int )); + +PGconn *pg_get_pgconn _(( VALUE )); +t_pg_connection *pg_get_connection _(( VALUE )); + VALUE pg_new_result _(( PGresult *, VALUE )); +VALUE pg_new_result_autoclear _(( PGresult *, VALUE )); +PGresult* pgresult_get _(( VALUE )); VALUE pg_result_check _(( VALUE )); VALUE pg_result_clear _(( VALUE )); +/* + * Fetch the data pointer for the result object + */ +static inline t_pg_result * +pgresult_get_this( VALUE self ) +{ + return DATA_PTR(self); +} + + #ifdef M17N_SUPPORTED rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int )); rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * )); const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * )); -int pg_enc_get_index _(( VALUE )); rb_encoding *pg_conn_enc_get _(( PGconn * )); #endif /* M17N_SUPPORTED */ void notice_receiver_proxy(void *arg, const PGresult *result); void notice_processor_proxy(void *arg, const char *message);