enhanced SQLSpecialColumns
Quan Zongliang <[email protected]> Wed, 14 Nov 2018 21:48:01 +0800
| Newsgroups | gmane.comp.db.postgresql.odbc |
|---|---|
| Message-ID | <[email protected]> |
hi, all patch attched,please review. If a table has not WITH OIDS option. Try to find primary-key(prefered)/unique index. If it has not either of them, returns "ctid" as text type. -- Quan Zongliang
specialcols.patch
(text/plain, 7.1 KB)
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; i<col_num; i++)
+ {
+ f_oid = QR_get_value_backend_oid(rowid_res, i, 0, NULL);
+ /* only returns first constraint */
+ if (conoid == InvalidOid)
+ conoid = f_oid;
+ else if (f_oid != conoid)
+ break;
+
+ f_type = QR_get_value_backend_int(rowid_res, i, 3, NULL);
+ f_mod = QR_get_value_backend_int(rowid_res, i, 4, NULL);
+
+ tuple = QR_AddNew(res);
+
+ set_tuplefield_int2(&tuple[SPECOLS_SCOPE], SQL_SCOPE_TRANSACTION);
+ set_tuplefield_string(&tuple[SPECOLS_COLUMN_NAME], QR_get_value_backend_text(rowid_res, i, 2));
+ set_tuplefield_int2(&tuple[SPECOLS_DATA_TYPE], PGTYPE_ATTR_TO_CONCISE_TYPE(conn, f_type, f_mod));
+ set_tuplefield_string(&tuple[SPECOLS_TYPE_NAME], pgtype_attr_to_name(conn, f_type, f_mod, FALSE));
+ set_tuplefield_int4(&tuple[SPECOLS_COLUMN_SIZE], PGTYPE_ATTR_COLUMN_SIZE(conn, f_type, f_mod));
+ set_tuplefield_int4(&tuple[SPECOLS_BUFFER_LENGTH], PGTYPE_ATTR_BUFFER_LENGTH(conn, f_type, f_mod));
+ set_tuplefield_int2(&tuple[SPECOLS_DECIMAL_DIGITS], PGTYPE_ATTR_DECIMAL_DIGITS(conn, f_type, f_mod));
+ set_tuplefield_int2(&tuple[SPECOLS_PSEUDO_COLUMN], SQL_PC_NOT_PSEUDO);
+ }
+
+ QR_Destructor(rowid_res);
+ ret = SQL_SUCCESS;
+ goto cleanup;
+ }
+
+ QR_Destructor(rowid_res);
+
+ the_type = PG_TYPE_TEXT;
+ atttypmod = -1;
+ tuple = QR_AddNew(res);
+
+ set_tuplefield_int2(&tuple[SPECOLS_SCOPE], SQL_SCOPE_CURROW);
+ set_tuplefield_string(&tuple[SPECOLS_COLUMN_NAME], CTID_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, FALSE));
+ 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);
+ }
+
+ ret = SQL_SUCCESS;
+ goto cleanup;
}
else if (fColType == SQL_ROWVER)
{
diff --git a/psqlodbc.h b/psqlodbc.h
index fad41e0..5a027c6 100644
--- a/psqlodbc.h
+++ b/psqlodbc.h
@@ -678,6 +678,7 @@ CSTR PRINT_NULL = "(null)";
#define OID_NAME "oid"
#define XMIN_NAME "xmin"
#define TABLEOID_NAME "tableoid"
+#define CTID_NAME "ctid"
enum
{
diff --git a/qresult.h b/qresult.h
index 652b4b7..e335020 100644
--- a/qresult.h
+++ b/qresult.h
@@ -133,6 +133,7 @@ enum {
#define QR_get_value_backend_row(self, tupleno, fieldno) ((self->backend_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))