/*
 * call-seq:
 *    PGConn.quote( obj )
 *    PGConn.quote( obj ){ |obj| ... }
 * 
 * If _obj_ is a +Number+, +String+, +Array+, +nil+, +true+, or +false+ then
 * #quote returns a String representation of that object safe for use in PostgreSQL.
 * 
 * If _obj_ is not one of the above classes and a block is supplied to #quote,
 * the block is invoked, passing along the object. The return value from the
 * block is returned as a string.
 *
 * If _obj_ is not one of the recognized classes and no block is supplied,
 * a PGError is raised.
 */
static VALUE
pgconn_s_quote(self, obj)
  VALUE self;
  VALUE obj;
{
  VALUE ret;
  char *to;
  long len;
  long idx;
  
  switch(TYPE(obj)) {
  case T_STRING:
    
    to = ALLOC_N(char, RSTRING(obj)->len * 2 + 2);
    
    *to = '\'';
    len = PQescapeString(to + 1, RSTRING(obj)->ptr, RSTRING(obj)->len);
    *(to + len + 1) = '\'';
    
    ret = rb_str_new(to, len + 2);
    OBJ_INFECT(ret, obj);
    
    free(to);
    break;
    
  case T_FIXNUM:
  case T_BIGNUM:
  case T_FLOAT:
    ret = rb_obj_as_string(obj);
    break;
    
  case T_NIL:
    ret = rb_str_new2("NULL");
    break;
    
  case T_TRUE:
    ret = rb_str_new2("'t'");
    break;
    
  case T_FALSE:
    ret = rb_str_new2("'f'");
    break;
    
  case T_ARRAY:
    ret = rb_str_new(0,0);
    len = RARRAY(obj)->len;
    for(idx=0; idx<len; idx++) {
    rb_str_concat(ret,  pgconn_s_quote(self, rb_ary_entry(obj, idx)));
    if (idx<len-1) {
      rb_str_cat2(ret, ", ");
    }
    }
    break;
  default:
    if (rb_block_given_p()==Qtrue) {
    ret = rb_yield(obj);
    } else {
    rb_raise(rb_ePGError, "can't quote");
    }
  }
  
  return ret;
}