diff --git a/info.c b/info.c index 052f0ae..a6e126e 100644 --- a/info.c +++ b/info.c @@ -2988,21 +2988,121 @@ MYLOG(DETAIL_LOG_LEVEL, "Add ctid\n"); Int2 the_type = PG_TYPE_OID; int atttypmod = -1; - if (relhasoids[0] != '1') + if (relhasoids[0] == '1') { - ret = SQL_SUCCESS; - goto cleanup; + tuple = QR_AddNew(res); + + set_tuplefield_int2(&tuple[SPECOLS_SCOPE], SQL_SCOPE_SESSION); + set_tuplefield_string(&tuple[SPECOLS_COLUMN_NAME], OID_NAME); + set_tuplefield_int2(&tuple[SPECOLS_DATA_TYPE], PGTYPE_ATTR_TO_CONCISE_TYPE(conn, the_type, atttypmod)); + set_tuplefield_string(&tuple[SPECOLS_TYPE_NAME], pgtype_attr_to_name(conn, the_type, atttypmod, TRUE)); + set_tuplefield_int4(&tuple[SPECOLS_COLUMN_SIZE], PGTYPE_ATTR_COLUMN_SIZE(conn, the_type, atttypmod)); + set_tuplefield_int4(&tuple[SPECOLS_BUFFER_LENGTH], PGTYPE_ATTR_BUFFER_LENGTH(conn, the_type, atttypmod)); + set_tuplefield_int2(&tuple[SPECOLS_DECIMAL_DIGITS], PGTYPE_ATTR_DECIMAL_DIGITS(conn, the_type, atttypmod)); + set_tuplefield_int2(&tuple[SPECOLS_PSEUDO_COLUMN], SQL_PC_PSEUDO); } - tuple = QR_AddNew(res); + else + { + OID conoid = InvalidOid; + QResultClass *rowid_res; + SQLULEN col_num; + + /* From 9.5, PG has array_position(). */ + /* Do not intend to support 9.4 and earlier */ + if (conn->pg_version_major<9 || + (conn->pg_version_major==9 && conn->pg_version_minor<5)) + { + ret = SQL_SUCCESS; + goto cleanup; + } - set_tuplefield_int2(&tuple[SPECOLS_SCOPE], SQL_SCOPE_SESSION); - set_tuplefield_string(&tuple[SPECOLS_COLUMN_NAME], OID_NAME); - set_tuplefield_int2(&tuple[SPECOLS_DATA_TYPE], PGTYPE_ATTR_TO_CONCISE_TYPE(conn, the_type, atttypmod)); - set_tuplefield_string(&tuple[SPECOLS_TYPE_NAME], pgtype_attr_to_name(conn, the_type, atttypmod, TRUE)); - set_tuplefield_int4(&tuple[SPECOLS_COLUMN_SIZE], PGTYPE_ATTR_COLUMN_SIZE(conn, the_type, atttypmod)); - set_tuplefield_int4(&tuple[SPECOLS_BUFFER_LENGTH], PGTYPE_ATTR_BUFFER_LENGTH(conn, the_type, atttypmod)); - set_tuplefield_int2(&tuple[SPECOLS_DECIMAL_DIGITS], PGTYPE_ATTR_DECIMAL_DIGITS(conn, the_type, atttypmod)); - set_tuplefield_int2(&tuple[SPECOLS_PSEUDO_COLUMN], SQL_PC_PSEUDO); + resetPQExpBuffer(&columns_query); + + appendPQExpBufferStr(&columns_query, "SELECT c.oid, c.contype, a.attname, a.atttypid, a.atttypmod"); + appendPQExpBufferStr(&columns_query, " FROM pg_catalog.pg_namespace n, pg_catalog.pg_class r"); + appendPQExpBufferStr(&columns_query, ", pg_constraint c, pg_attribute a "); + appendPQExpBufferStr(&columns_query, "WHERE n.oid = r.relnamespace AND c.conrelid = r.oid "); + appendPQExpBufferStr(&columns_query, "AND (contype = 'p' OR contype = 'u') "); + appendPQExpBufferStr(&columns_query, "AND a.attrelid = r.oid AND a.attnum = ANY(c.conkey) "); + if (escTableName) + appendPQExpBuffer(&columns_query, + "AND r.relname %s'%s' ", eq_string, escTableName); + + schema_appendPQExpBuffer1(&columns_query, "AND n.nspname %s'%.*s' ", eq_string, escSchemaName, + TABLE_IS_VALID(szTableName, cbTableName), conn); + /* "ORDER BY c.contype" keep primary key first(if exists) */ + appendPQExpBufferStr(&columns_query, "ORDER BY c.contype,array_position(c.conkey, a.attnum)"); + + if (PQExpBufferDataBroken(columns_query)) + { + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Out of memory in PGAPI_SpecialColumns()", func); + goto cleanup; + } + + rowid_res = CC_send_query(conn, columns_query.data, NULL, READ_ONLY_QUERY, stmt); + if (!QR_command_maybe_successful(rowid_res)) + { + SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_SpecialColumns query error", func); + QR_Destructor(rowid_res); + goto cleanup; + } + + /* has primary key */ + col_num = QR_get_num_total_tuples(rowid_res); + if (col_num > 0) + { + SQLULEN i; + OID f_oid; + OID f_type; + int f_mod; + + for (i=0; ibackend_tuples + (tupleno * self->num_fields))[fieldno].value) #define QR_get_value_backend_text(self, tupleno, fieldno) QR_get_value_backend_row(self, tupleno, fieldno) #define QR_get_value_backend_int(self, tupleno, fieldno, isNull) atoi(QR_get_value_backend_row(self, tupleno, fieldno)) +#define QR_get_value_backend_oid(self, tupleno, fieldno, isNull) atooid(QR_get_value_backend_row(self, tupleno, fieldno)) /* These functions are used by both manual and backend results */ #define QR_NumResultCols(self) (CI_get_num_fields(self->fields))