/* * call-seq: * conn.exec_prepared(statement_name [, params, result_format ] ) -> PGresult * conn.exec_prepared(statement_name [, params, result_format ] ) {|pg_result| block } * * Execute prepared named statement specified by _statement_name_. * Returns a PGresult instance on success. * On failure, it raises a PGError exception. * * +params+ is an array of the optional bind parameters for the * SQL query. Each element of the +params+ array may be either: * a hash of the form: * {:value => String (value of bind parameter) * :format => Fixnum (0 for text, 1 for binary) * } * or, it may be a String. If it is a string, that is equivalent to the hash: * { :value => <string value>, :format => 0 } * * PostgreSQL bind parameters are represented as $1, $1, $2, etc., * inside the SQL query. The 0th element of the +params+ array is bound * to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+. * * The optional +result_format+ should be 0 for text results, 1 * for binary. * * If the optional code block is given, it will be passed <i>result</i> as an argument, * and the PGresult object will automatically be cleared when the block terminates. * In this instance, <code>conn.exec_prepared</code> returns the value of the block. */ static VALUE pgconn_exec_prepared(int argc, VALUE *argv, VALUE self) { PGconn *conn = get_pgconn(self); PGresult *result = NULL; VALUE rb_pgresult; VALUE name, params, in_res_fmt; VALUE param, param_value, param_format; VALUE param_value_tmp; VALUE sym_value, sym_format; VALUE gc_array; int i = 0; int nParams; char ** paramValues; int *paramLengths; int *paramFormats; int resultFormat; rb_scan_args(argc, argv, "12", &name, ¶ms, &in_res_fmt); Check_Type(name, T_STRING); if(NIL_P(params)) { params = rb_ary_new2(0); resultFormat = 0; } else { Check_Type(params, T_ARRAY); } if(NIL_P(in_res_fmt)) { resultFormat = 0; } else { resultFormat = NUM2INT(in_res_fmt); } gc_array = rb_ary_new(); rb_gc_register_address(&gc_array); sym_value = ID2SYM(rb_intern("value")); sym_format = ID2SYM(rb_intern("format")); nParams = RARRAY_LEN(params); paramValues = ALLOC_N(char *, nParams); paramLengths = ALLOC_N(int, nParams); paramFormats = ALLOC_N(int, nParams); for(i = 0; i < nParams; i++) { param = rb_ary_entry(params, i); if (TYPE(param) == T_HASH) { param_value_tmp = rb_hash_aref(param, sym_value); if(param_value_tmp == Qnil) param_value = param_value_tmp; else param_value = rb_obj_as_string(param_value_tmp); param_format = rb_hash_aref(param, sym_format); } else { if(param == Qnil) param_value = param; else param_value = rb_obj_as_string(param); param_format = INT2NUM(0); } if(param_value == Qnil) { paramValues[i] = NULL; paramLengths[i] = 0; } else { Check_Type(param_value, T_STRING); /* make sure param_value doesn't get freed by the GC */ rb_ary_push(gc_array, param_value); paramValues[i] = StringValuePtr(param_value); paramLengths[i] = RSTRING_LEN(param_value); } if(param_format == Qnil) paramFormats[i] = 0; else paramFormats[i] = NUM2INT(param_format); } result = PQexecPrepared(conn, StringValuePtr(name), nParams, (const char * const *)paramValues, paramLengths, paramFormats, resultFormat); rb_gc_unregister_address(&gc_array); xfree(paramValues); xfree(paramLengths); xfree(paramFormats); rb_pgresult = new_pgresult(result, conn); pgresult_check(self, rb_pgresult); if (rb_block_given_p()) { return rb_ensure(rb_yield, rb_pgresult, pgresult_clear, rb_pgresult); } return rb_pgresult; }