ext/pg_connection.c in pg-0.18.4 vs ext/pg_connection.c in pg-0.19.0.pre20160409114042
- old
+ new
@@ -1,8 +1,8 @@
/*
* pg_connection.c - PG::Connection class extension
- * $Id: pg_connection.c,v eb4d3c003bd6 2015/05/25 20:04:04 ged $
+ * $Id: pg_connection.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
*
*/
#include "pg.h"
@@ -50,11 +50,11 @@
/*
* Fetch the PG::Connection object data pointer and check it's
* PGconn data pointer for sanity.
*/
-t_pg_connection *
+static t_pg_connection *
pg_get_connection_safe( VALUE self )
{
t_pg_connection *this;
Data_Get_Struct( self, t_pg_connection, this);
@@ -86,11 +86,11 @@
/*
* Close the associated socket IO object if there is one.
*/
-void
+static void
pgconn_close_socket_io( VALUE self )
{
t_pg_connection *this = pg_get_connection( self );
VALUE socket_io = this->socket_io;
@@ -139,11 +139,21 @@
}
return ary;
}
+static const char *pg_cstr_enc(VALUE str, int enc_idx){
+ const char *ptr = StringValueCStr(str);
+ if( ENCODING_GET(str) == enc_idx ){
+ return ptr;
+ } else {
+ str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
+ return StringValueCStr(str);
+ }
+}
+
/*
* GC Mark function
*/
static void
pgconn_gc_mark( t_pg_connection *this )
@@ -371,11 +381,11 @@
}
#endif
/*
- * Document-method: conndefaults
+ * Document-method: PG::Connection.conndefaults
*
* call-seq:
* PG::Connection.conndefaults() -> Array
*
* Returns an array of hashes. Each hash has the keys:
@@ -945,13 +955,13 @@
PGresult *result = NULL;
VALUE rb_pgresult;
/* If called with no parameters, use PQexec */
if ( argc == 1 ) {
- Check_Type(argv[0], T_STRING);
+ VALUE query_str = argv[0];
- result = gvl_PQexec(conn, StringValueCStr(argv[0]));
+ result = gvl_PQexec(conn, pg_cstr_enc(query_str, ENCODING_GET(self)));
rb_pgresult = pg_new_result(result, self);
pg_result_check(rb_pgresult);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, rb_pgresult, pg_result_clear, rb_pgresult);
}
@@ -976,10 +986,14 @@
/*
* Filled by caller
*/
+ /* The character encoding index of the connection. Any strings
+ * given as query parameters are converted to this encoding.
+ */
+ int enc_idx;
/* Is the query function to execute one with types array? */
int with_types;
/* Array of query params from user space */
VALUE params;
/* The typemap given from user space */
@@ -1136,11 +1150,11 @@
} else {
t_pg_coder_enc_func enc_func = pg_coder_enc_func( conv );
VALUE intermediate;
/* 1st pass for retiving the required memory space */
- int len = enc_func(conv, param_value, NULL, &intermediate);
+ int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
if( len == -1 ){
/* The intermediate value is a String that can be used directly. */
/* Ensure that the String object is zero terminated as expected by libpq. */
@@ -1160,11 +1174,11 @@
if( sizeof(paramsData->memory_pool) < required_pool_size + len + 1){
typecast_buf = alloc_typecast_buf( ¶msData->typecast_heap_chain, len + 1 );
}
/* 2nd pass for writing the data to prepared buffer */
- len = enc_func(conv, param_value, typecast_buf, &intermediate);
+ len = enc_func(conv, param_value, typecast_buf, &intermediate, paramsData->enc_idx);
paramsData->values[i] = typecast_buf;
if( paramsData->formats[i] == 0 ){
/* text format strings must be zero terminated and lengths are ignored */
typecast_buf[len] = 0;
typecast_buf += len + 1;
@@ -1256,11 +1270,11 @@
PGresult *result = NULL;
VALUE rb_pgresult;
VALUE command, in_res_fmt;
int nParams;
int resultFormat;
- struct query_params_data paramsData;
+ struct query_params_data paramsData = { ENCODING_GET(self) };
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
paramsData.with_types = 1;
/*
@@ -1273,11 +1287,11 @@
pgconn_query_assign_typemap( self, ¶msData );
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
nParams = alloc_query_params( ¶msData );
- result = gvl_PQexecParams(conn, StringValueCStr(command), nParams, paramsData.types,
+ result = gvl_PQexecParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
free_query_params( ¶msData );
rb_pgresult = pg_new_result(result, self);
@@ -1319,14 +1333,17 @@
VALUE name, command, in_paramtypes;
VALUE param;
int i = 0;
int nParams = 0;
Oid *paramTypes = NULL;
+ const char *name_cstr;
+ const char *command_cstr;
+ int enc_idx = ENCODING_GET(self);
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
- Check_Type(name, T_STRING);
- Check_Type(command, T_STRING);
+ name_cstr = pg_cstr_enc(name, enc_idx);
+ command_cstr = pg_cstr_enc(command, enc_idx);
if(! NIL_P(in_paramtypes)) {
Check_Type(in_paramtypes, T_ARRAY);
nParams = (int)RARRAY_LEN(in_paramtypes);
paramTypes = ALLOC_N(Oid, nParams);
@@ -1336,12 +1353,11 @@
paramTypes[i] = 0;
else
paramTypes[i] = NUM2UINT(param);
}
}
- result = gvl_PQprepare(conn, StringValueCStr(name), StringValueCStr(command),
- nParams, paramTypes);
+ result = gvl_PQprepare(conn, name_cstr, command_cstr, nParams, paramTypes);
xfree(paramTypes);
rb_pgresult = pg_new_result(result, self);
pg_result_check(rb_pgresult);
@@ -1390,25 +1406,24 @@
PGresult *result = NULL;
VALUE rb_pgresult;
VALUE name, in_res_fmt;
int nParams;
int resultFormat;
- struct query_params_data paramsData;
+ struct query_params_data paramsData = { ENCODING_GET(self) };
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
paramsData.with_types = 0;
- Check_Type(name, T_STRING);
if(NIL_P(paramsData.params)) {
paramsData.params = rb_ary_new2(0);
}
pgconn_query_assign_typemap( self, ¶msData );
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
nParams = alloc_query_params( ¶msData );
- result = gvl_PQexecPrepared(conn, StringValueCStr(name), nParams,
+ result = gvl_PQexecPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
resultFormat);
free_query_params( ¶msData );
@@ -1432,17 +1447,16 @@
pgconn_describe_prepared(VALUE self, VALUE stmt_name)
{
PGresult *result;
VALUE rb_pgresult;
PGconn *conn = pg_get_pgconn(self);
- char *stmt;
- if(stmt_name == Qnil) {
+ const char *stmt;
+ if(NIL_P(stmt_name)) {
stmt = NULL;
}
else {
- Check_Type(stmt_name, T_STRING);
- stmt = StringValueCStr(stmt_name);
+ stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
}
result = gvl_PQdescribePrepared(conn, stmt);
rb_pgresult = pg_new_result(result, self);
pg_result_check(rb_pgresult);
return rb_pgresult;
@@ -1460,17 +1474,16 @@
VALUE self, stmt_name;
{
PGresult *result;
VALUE rb_pgresult;
PGconn *conn = pg_get_pgconn(self);
- char *stmt;
- if(stmt_name == Qnil) {
+ const char *stmt;
+ if(NIL_P(stmt_name)) {
stmt = NULL;
}
else {
- Check_Type(stmt_name, T_STRING);
- stmt = StringValueCStr(stmt_name);
+ stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
}
result = gvl_PQdescribePortal(conn, stmt);
rb_pgresult = pg_new_result(result, self);
pg_result_check(rb_pgresult);
return rb_pgresult;
@@ -1508,63 +1521,61 @@
/*
* call-seq:
* conn.escape_string( str ) -> String
*
- * Connection instance method for versions of 8.1 and higher of libpq
- * uses PQescapeStringConn, which is safer. Avoid calling as a class method,
- * the class method uses the deprecated PQescapeString() API function.
- *
* Returns a SQL-safe version of the String _str_.
* This is the preferred way to make strings safe for inclusion in
* SQL queries.
*
* Consider using exec_params, which avoids the need for passing values
* inside of SQL commands.
*
* Encoding of escaped string will be equal to client encoding of connection.
+ *
+ * NOTE: This class version of this method can only be used safely in client
+ * programs that use a single PostgreSQL connection at a time (in this case it can
+ * find out what it needs to know "behind the scenes"). It might give the wrong
+ * results if used in programs that use multiple database connections; use the
+ * same method on the connection object in such cases.
*/
static VALUE
pgconn_s_escape(VALUE self, VALUE string)
{
- char *escaped;
size_t size;
int error;
VALUE result;
+ int enc_idx;
+ int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
Check_Type(string, T_STRING);
+ enc_idx = ENCODING_GET( singleton ? string : self );
+ if( ENCODING_GET(string) != enc_idx ){
+ string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
+ }
- escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
- if( rb_obj_is_kind_of(self, rb_cPGconn) ) {
- size = PQescapeStringConn(pg_get_pgconn(self), escaped,
+ result = rb_str_new(NULL, RSTRING_LEN(string) * 2 + 1);
+ PG_ENCODING_SET_NOCHECK(result, enc_idx);
+ if( !singleton ) {
+ size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
RSTRING_PTR(string), RSTRING_LEN(string), &error);
if(error) {
- xfree(escaped);
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
}
} else {
- size = PQescapeString(escaped, RSTRING_PTR(string), RSTRING_LENINT(string));
+ size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
}
- result = rb_str_new(escaped, size);
- xfree(escaped);
+ rb_str_set_len(result, size);
OBJ_INFECT(result, string);
- PG_ENCODING_SET_NOCHECK(result, ENCODING_GET( rb_obj_is_kind_of(self, rb_cPGconn) ? self : string ));
return result;
}
/*
* call-seq:
* conn.escape_bytea( string ) -> String
*
- * Connection instance method for versions of 8.1 and higher of libpq
- * uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
- * the class method uses the deprecated PQescapeBytea() API function.
- *
- * Use the instance method version of this function, it is safer than the
- * class method.
- *
* Escapes binary data for use within an SQL command with the type +bytea+.
*
* Certain byte values must be escaped (but all byte values may be escaped)
* when used as part of a +bytea+ literal in an SQL statement. In general, to
* escape a byte, it is converted into the three digit octal number equal to
@@ -1573,10 +1584,16 @@
* #escape_bytea performs this operation, escaping only the minimally required
* bytes.
*
* Consider using exec_params, which avoids the need for passing values inside of
* SQL commands.
+ *
+ * NOTE: This class version of this method can only be used safely in client
+ * programs that use a single PostgreSQL connection at a time (in this case it can
+ * find out what it needs to know "behind the scenes"). It might give the wrong
+ * results if used in programs that use multiple database connections; use the
+ * same method on the connection object in such cases.
*/
static VALUE
pgconn_s_escape_bytea(VALUE self, VALUE str)
{
unsigned char *from, *to;
@@ -1641,12 +1658,16 @@
{
PGconn *conn = pg_get_pgconn(self);
char *escaped = NULL;
VALUE error;
VALUE result = Qnil;
+ int enc_idx = ENCODING_GET(self);
Check_Type(string, T_STRING);
+ if( ENCODING_GET(string) != enc_idx ){
+ string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
+ }
escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
if (escaped == NULL)
{
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
@@ -1655,11 +1676,11 @@
return Qnil;
}
result = rb_str_new2(escaped);
PQfreemem(escaped);
OBJ_INFECT(result, string);
- PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
+ PG_ENCODING_SET_NOCHECK(result, enc_idx);
return result;
}
#endif
@@ -1668,22 +1689,27 @@
* call-seq:
* conn.escape_identifier( str ) -> String
*
* Escape an arbitrary String +str+ as an identifier.
*
- * This method does the same as #quote_ident, but uses libpq to
- * process the string.
+ * This method does the same as #quote_ident with a String argument,
+ * but it doesn't support an Array argument and it makes use of libpq
+ * to process the string.
*/
static VALUE
pgconn_escape_identifier(VALUE self, VALUE string)
{
PGconn *conn = pg_get_pgconn(self);
char *escaped = NULL;
VALUE error;
VALUE result = Qnil;
+ int enc_idx = ENCODING_GET(self);
Check_Type(string, T_STRING);
+ if( ENCODING_GET(string) != enc_idx ){
+ string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
+ }
escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
if (escaped == NULL)
{
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
@@ -1692,11 +1718,11 @@
return Qnil;
}
result = rb_str_new2(escaped);
PQfreemem(escaped);
OBJ_INFECT(result, string);
- PG_ENCODING_SET_NOCHECK(result, ENCODING_GET(self));
+ PG_ENCODING_SET_NOCHECK(result, enc_idx);
return result;
}
#endif
@@ -1800,19 +1826,18 @@
int result;
VALUE command, in_res_fmt;
VALUE error;
int nParams;
int resultFormat;
- struct query_params_data paramsData;
+ struct query_params_data paramsData = { ENCODING_GET(self) };
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
paramsData.with_types = 1;
- Check_Type(command, T_STRING);
/* If called with no parameters, use PQsendQuery */
if(NIL_P(paramsData.params)) {
- if(gvl_PQsendQuery(conn,StringValueCStr(command)) == 0) {
+ if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
rb_iv_set(error, "@connection", self);
rb_exc_raise(error);
}
return Qnil;
@@ -1824,11 +1849,11 @@
pgconn_query_assign_typemap( self, ¶msData );
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
nParams = alloc_query_params( ¶msData );
- result = gvl_PQsendQueryParams(conn, StringValueCStr(command), nParams, paramsData.types,
+ result = gvl_PQsendQueryParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
free_query_params( ¶msData );
if(result == 0) {
@@ -1868,14 +1893,17 @@
VALUE param;
VALUE error;
int i = 0;
int nParams = 0;
Oid *paramTypes = NULL;
+ const char *name_cstr;
+ const char *command_cstr;
+ int enc_idx = ENCODING_GET(self);
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
- Check_Type(name, T_STRING);
- Check_Type(command, T_STRING);
+ name_cstr = pg_cstr_enc(name, enc_idx);
+ command_cstr = pg_cstr_enc(command, enc_idx);
if(! NIL_P(in_paramtypes)) {
Check_Type(in_paramtypes, T_ARRAY);
nParams = (int)RARRAY_LEN(in_paramtypes);
paramTypes = ALLOC_N(Oid, nParams);
@@ -1885,12 +1913,11 @@
paramTypes[i] = 0;
else
paramTypes[i] = NUM2UINT(param);
}
}
- result = gvl_PQsendPrepare(conn, StringValueCStr(name), StringValueCStr(command),
- nParams, paramTypes);
+ result = gvl_PQsendPrepare(conn, name_cstr, command_cstr, nParams, paramTypes);
xfree(paramTypes);
if(result == 0) {
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
@@ -1939,26 +1966,25 @@
int result;
VALUE name, in_res_fmt;
VALUE error;
int nParams;
int resultFormat;
- struct query_params_data paramsData;
+ struct query_params_data paramsData = { ENCODING_GET(self) };
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
paramsData.with_types = 0;
- Check_Type(name, T_STRING);
if(NIL_P(paramsData.params)) {
paramsData.params = rb_ary_new2(0);
resultFormat = 0;
}
pgconn_query_assign_typemap( self, ¶msData );
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
nParams = alloc_query_params( ¶msData );
- result = gvl_PQsendQueryPrepared(conn, StringValueCStr(name), nParams,
+ result = gvl_PQsendQueryPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
resultFormat);
free_query_params( ¶msData );
@@ -1981,11 +2007,11 @@
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
{
VALUE error;
PGconn *conn = pg_get_pgconn(self);
/* returns 0 on failure */
- if(gvl_PQsendDescribePrepared(conn,StringValueCStr(stmt_name)) == 0) {
+ if(gvl_PQsendDescribePrepared(conn, pg_cstr_enc(stmt_name, ENCODING_GET(self))) == 0) {
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
rb_iv_set(error, "@connection", self);
rb_exc_raise(error);
}
return Qnil;
@@ -2003,11 +2029,11 @@
pgconn_send_describe_portal(VALUE self, VALUE portal)
{
VALUE error;
PGconn *conn = pg_get_pgconn(self);
/* returns 0 on failure */
- if(gvl_PQsendDescribePortal(conn,StringValueCStr(portal)) == 0) {
+ if(gvl_PQsendDescribePortal(conn, pg_cstr_enc(portal, ENCODING_GET(self))) == 0) {
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
rb_iv_set(error, "@connection", self);
rb_exc_raise(error);
}
return Qnil;
@@ -2563,20 +2589,21 @@
rb_obj_classname( encoder ) );
}
if( p_coder ){
t_pg_coder_enc_func enc_func;
+ int enc_idx = ENCODING_GET(self);
enc_func = pg_coder_enc_func( p_coder );
- len = enc_func( p_coder, value, NULL, &intermediate );
+ len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
if( len == -1 ){
/* The intermediate value is a String that can be used directly. */
buffer = intermediate;
} else {
buffer = rb_str_new(NULL, len);
- len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate);
+ len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate, enc_idx);
rb_str_set_len( buffer, len );
}
}
Check_Type(buffer, T_STRING);
@@ -2611,17 +2638,17 @@
pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
{
VALUE str;
VALUE error;
int ret;
- char *error_message = NULL;
+ const char *error_message = NULL;
PGconn *conn = pg_get_pgconn(self);
if (rb_scan_args(argc, argv, "01", &str) == 0)
error_message = NULL;
else
- error_message = StringValueCStr(str);
+ error_message = pg_cstr_enc(str, ENCODING_GET(self));
ret = gvl_PQputCopyEnd(conn, error_message);
if(ret == -1) {
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
rb_iv_set(error, "@connection", self);
@@ -2994,24 +3021,24 @@
}
/*
* call-seq:
- * PG::Connection.quote_ident( str ) -> String
- * PG::Connection.quote_ident( array ) -> String
* conn.quote_ident( str ) -> String
* conn.quote_ident( array ) -> String
+ * PG::Connection.quote_ident( str ) -> String
+ * PG::Connection.quote_ident( array ) -> String
*
* Returns a string that is safe for inclusion in a SQL query as an
* identifier. Note: this is not a quote function for values, but for
* identifiers.
*
* For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
* means <tt>foo</tt>. If you really want to access the case-sensitive
* field name <tt>FOO</tt>, use this function like
- * <tt>PG::Connection.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
+ * <tt>conn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
* (with double-quotes). PostgreSQL will see the double-quotes, and
* it will not fold to lower case.
*
* Similarly, this function also protects against special characters,
* and other things that might allow SQL injection if the identifier
@@ -3021,20 +3048,32 @@
* and then joined by a "." character. This can be used for identifiers in
* the form "schema"."table"."column" .
*
* This method is functional identical to the encoder PG::TextEncoder::Identifier .
*
+ * If the instance method form is used and the input string character encoding
+ * is different to the connection encoding, then the string is converted to this
+ * encoding, so that the returned string is always encoded as PG::Connection#internal_encoding .
+ *
+ * In the singleton form (PG::Connection.quote_ident) the character encoding
+ * of the result string is set to the character encoding of the input string.
*/
static VALUE
-pgconn_s_quote_ident(VALUE self, VALUE in_str)
+pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
{
VALUE ret;
- pg_text_enc_identifier(NULL, in_str, NULL, &ret);
+ int enc_idx;
- OBJ_INFECT(ret, in_str);
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET( rb_obj_is_kind_of(self, rb_cPGconn) ? self : in_str ));
+ if( rb_obj_is_kind_of(self, rb_cPGconn) ){
+ enc_idx = ENCODING_GET( self );
+ }else{
+ enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
+ }
+ pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
+ OBJ_INFECT(ret, str_or_array);
+
return ret;
}
static void *
@@ -3155,10 +3194,88 @@
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
}
return rb_pgresult;
}
+
+#ifdef HAVE_PQSSLATTRIBUTE
+/* Since PostgreSQL-9.5: */
+
+/*
+ * call-seq:
+ * conn.ssl_in_use? -> Boolean
+ *
+ * Returns +true+ if the connection uses SSL, +false+ if not.
+ *
+ */
+static VALUE
+pgconn_ssl_in_use(VALUE self)
+{
+ return PQsslInUse(pg_get_pgconn(self)) ? Qtrue : Qfalse;
+}
+
+
+/*
+ * call-seq:
+ * conn.ssl_attribute(attribute_name) -> String
+ *
+ * Returns SSL-related information about the connection.
+ *
+ * The list of available attributes varies depending on the SSL library being used,
+ * and the type of connection. If an attribute is not available, returns nil.
+ *
+ * The following attributes are commonly available:
+ *
+ * [+library+]
+ * Name of the SSL implementation in use. (Currently, only "OpenSSL" is implemented)
+ * [+protocol+]
+ * SSL/TLS version in use. Common values are "SSLv2", "SSLv3", "TLSv1", "TLSv1.1" and "TLSv1.2", but an implementation may return other strings if some other protocol is used.
+ * [+key_bits+]
+ * Number of key bits used by the encryption algorithm.
+ * [+cipher+]
+ * A short name of the ciphersuite used, e.g. "DHE-RSA-DES-CBC3-SHA". The names are specific to each SSL implementation.
+ * [+compression+]
+ * If SSL compression is in use, returns the name of the compression algorithm, or "on" if compression is used but the algorithm is not known. If compression is not in use, returns "off".
+ *
+ *
+ * See also #ssl_attribute_names and http://www.postgresql.org/docs/current/interactive/libpq-status.html#LIBPQ-PQSSLATTRIBUTE
+ */
+static VALUE
+pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
+{
+ const char *p_attr;
+
+ p_attr = PQsslAttribute(pg_get_pgconn(self), StringValueCStr(attribute_name));
+ return p_attr ? rb_str_new_cstr(p_attr) : Qnil;
+}
+
+/*
+ * call-seq:
+ * conn.ssl_attribute_names -> Array<String>
+ *
+ * Return an array of SSL attribute names available.
+ *
+ * See also #ssl_attribute
+ *
+ */
+static VALUE
+pgconn_ssl_attribute_names(VALUE self)
+{
+ int i;
+ const char * const * p_list = PQsslAttributeNames(pg_get_pgconn(self));
+ VALUE ary = rb_ary_new();
+
+ for ( i = 0; p_list[i]; i++ ) {
+ rb_ary_push( ary, rb_str_new_cstr( p_list[i] ));
+ }
+ return ary;
+}
+
+
+#endif
+
+
/**************************************************************************
* LARGE OBJECT SUPPORT
**************************************************************************/
/*
@@ -3702,11 +3819,11 @@
* Returns the default coder object that is currently set for type casting of parameters
* to #put_copy_data .
*
* Returns either:
* * a kind of PG::Coder
- * * +nil+ - type encoding is disabled, returned data will be a String.
+ * * +nil+ - type encoding is disabled, data must be a String.
*
*/
static VALUE
pgconn_encoder_for_put_copy_data_get(VALUE self)
{
@@ -3763,10 +3880,13 @@
return this->decoder_for_get_copy_data;
}
+/*
+ * Document-class: PG::Connection
+ */
void
init_pg_connection()
{
s_id_encode = rb_intern("encode");
sym_type = ID2SYM(rb_intern("type"));
@@ -3898,9 +4018,15 @@
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
+
+#ifdef HAVE_PQSSLATTRIBUTE
+ rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
+ rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
+ rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
+#endif
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
rb_define_method(rb_cPGconn, "lo_create", pgconn_locreate, 1);