Skip to content

Commit 6b84d23

Browse files
authored
fix PGAPI_SpecialColumns to the best rowid (#124)
* add info.c * add tests for unique indexes
1 parent 53d91b4 commit 6b84d23

File tree

4 files changed

+124
-50
lines changed

4 files changed

+124
-50
lines changed

info.c

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2902,6 +2902,52 @@ MYLOG(0, " and the data=%s\n", attdef);
29022902
return ret;
29032903
}
29042904

2905+
/** @brief Retrieve the primary or unique key columns for the specified table
2906+
*
2907+
* @param conn ConnectionClass
2908+
* @param stmt StatementClass
2909+
* @param szTableName Table name
2910+
* @param szTableQualifier Schema name
2911+
* @param szSchemaName Schema name
2912+
* @return QResultClass
2913+
*/
2914+
static QResultClass *
2915+
findPrimaryOrUnique(ConnectionClass *conn, StatementClass * stmt, const SQLCHAR * szTableName, const SQLCHAR *szTableQualifier, const SQLCHAR * szSchemaName, bool primaryOrUnique) {
2916+
PQExpBufferData columns_query = {0};
2917+
2918+
initPQExpBuffer(&columns_query);
2919+
printfPQExpBuffer(&columns_query, "select NULL as \"SCOPE\","
2920+
"a.attname AS \"COLUMN_NAME\","
2921+
"t.typname AS \"DATA_TYPE\","
2922+
"t.typname AS \"TYPE_NAME\","
2923+
"t.typlen AS \"COLUMN_SIZE\","
2924+
"a.attlen AS \"BUFFER_LENGTH\","
2925+
"case "
2926+
"when t.typname = 'numeric' then"
2927+
" case when a.atttypmod > -1 then 6"
2928+
" else a.atttypmod::int4"
2929+
" end"
2930+
" else 0"
2931+
" end AS \"DECIMAL_DIGITS\","
2932+
"1 AS \"PSEUDO_COLUMN\" "
2933+
"FROM pg_class c "
2934+
"INNER JOIN pg_namespace n ON n.oid = c.relnamespace "
2935+
"INNER JOIN pg_attribute a ON a.attrelid = c.oid "
2936+
"INNER JOIN pg_type t on a.atttypid = t.oid "
2937+
"LEFT JOIN pg_index i ON i.indrelid = c.oid "
2938+
"AND a.attnum = ANY (i.indkey[0:(i.indnkeyatts - 1)]) ");
2939+
if (primaryOrUnique) {
2940+
appendPQExpBuffer(&columns_query, "WHERE i.indisprimary and a.attnum > 0 and c.relname='%s'" , szTableName );
2941+
} else {
2942+
appendPQExpBuffer(&columns_query, "WHERE i.indisunique and a.attnum > 0 and c.relname ='%s'", szTableName);
2943+
}
2944+
2945+
2946+
if (szTableQualifier != NULL)
2947+
appendPQExpBuffer(&columns_query, " and n.nspname = '%s'" , szSchemaName);
2948+
2949+
return CC_send_query(conn, columns_query.data, NULL, READ_ONLY_QUERY, stmt);
2950+
}
29052951

29062952
/** @brief Retrieve the optimal set of columns that uniquely identifies a row in the specified table (when IdentifierType is SQL_BEST_ROWID)
29072953
* The columns that are automatically updated when any value in the row is updated (when IdentifierType is SQL_ROWVER)
@@ -3146,57 +3192,25 @@ PGAPI_SpecialColumns(HSTMT hstmt,
31463192
set_tuplefield_int4(&tuple[SPECOLS_BUFFER_LENGTH], PGTYPE_ATTR_BUFFER_LENGTH(conn, the_type, atttypmod));
31473193
set_tuplefield_int2(&tuple[SPECOLS_DECIMAL_DIGITS], PGTYPE_ATTR_DECIMAL_DIGITS(conn, the_type, atttypmod));
31483194
set_tuplefield_int2(&tuple[SPECOLS_PSEUDO_COLUMN], SQL_PC_PSEUDO);
3149-
} else {
3150-
/*
3151-
3152-
SELECT NULL as \"SCOPE\",
3153-
n.nspname AS \"SCHEMA_NAME\"",
3154-
c.relname AS \"TABLE_NAME\"",
3155-
a.attname AS \"COLUMN_NAME\"",
3156-
t.typname AS \"DATA_TYPE\",
3157-
t.typename AS \"TYPE_NAME\"",
3158-
i.indisunique,i.indisprimary
3159-
FROM pg_class c
3160-
INNER JOIN pg_namespace n ON n.oid = c.relnamespace
3161-
INNER JOIN pg_attribute a ON a.attrelid = c.oid
3162-
INNER JOIN pg_type t on a.atttypid = t.oid
3163-
LEFT JOIN pg_index i
3164-
ON i.indrelid = c.oid
3165-
AND a.attnum = ANY (i.indkey[0:(i.indnkeyatts - 1)])
3166-
WHERE a.attnum > 0 and c.relname like 'testuktab';
3167-
*/
3168-
initPQExpBuffer(&columns_query);
3169-
printfPQExpBuffer(&columns_query, "select NULL as \"SCOPE\","
3170-
"a.attname AS \"COLUMN_NAME\","
3171-
"t.typname AS \"DATA_TYPE\","
3172-
"t.typname AS \"TYPE_NAME\","
3173-
"t.typlen AS \"COLUMN_SIZE\","
3174-
"a.attlen AS \"BUFFER_LENGTH\","
3175-
"case "
3176-
"when t.typname = 'numeric' then"
3177-
" case when a.atttypmod > -1 then 6"
3178-
" else a.atttypmod::int4"
3179-
" end"
3180-
" else 0"
3181-
" end AS \"DECIMAL_DIGITS\","
3182-
"1 AS \"PSEUDO_COLUMN\" "
3183-
"FROM pg_class c "
3184-
"INNER JOIN pg_namespace n ON n.oid = c.relnamespace "
3185-
"INNER JOIN pg_attribute a ON a.attrelid = c.oid "
3186-
"INNER JOIN pg_type t on a.atttypid = t.oid "
3187-
"LEFT JOIN pg_index i ON i.indrelid = c.oid "
3188-
"AND a.attnum = ANY (i.indkey[0:(i.indnkeyatts - 1)]) "
3189-
"WHERE i.indisunique and a.attnum > 0 and c.relname ='%s'" , szTableName );
3190-
3191-
3192-
if (szTableQualifier != NULL)
3193-
appendPQExpBuffer(&columns_query, " and c.relnamespace = %s" , szSchemaName);
3194-
3195-
if (res = CC_send_query(conn, columns_query.data, NULL, READ_ONLY_QUERY, stmt), !QR_command_maybe_successful(res))
3195+
} else {
3196+
// look for primary first
3197+
res = findPrimaryOrUnique(conn, stmt, szTableName, szTableQualifier, szSchemaName, TRUE);
3198+
if (!QR_command_maybe_successful(res))
31963199
{
31973200
SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Special query error", func);
31983201
goto cleanup;
31993202
}
3203+
if (0 == QR_get_num_total_tuples(res))
3204+
{
3205+
// didn't find primary now look for uniaue
3206+
res = findPrimaryOrUnique(conn, stmt, szTableName, szTableName, szSchemaName, FALSE);
3207+
if (!QR_command_maybe_successful(res))
3208+
{
3209+
SC_set_error(stmt, STMT_EXEC_ERROR, "PGAPI_Special query error", func);
3210+
goto cleanup;
3211+
}
3212+
}
3213+
32003214
SC_set_Result(stmt, res);
32013215
}
32023216
}

test/expected/catalogfunctions.out

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ contrib_regression public byteatab TABLE
3535
contrib_regression public intervaltable TABLE
3636
contrib_regression public lo_test_tab TABLE
3737
contrib_regression public test_special TABLE
38+
contrib_regression public test_special_primary TABLE
3839
contrib_regression public testforeign FOREIGN TABLE
3940
contrib_regression public testmatview MATVIEW
4041
contrib_regression public testtab1 TABLE
@@ -81,6 +82,10 @@ contrib_regression public lo_test_tab large_data -4 lo
8182
contrib_regression public test_special id 4 int4
8283
contrib_regression public test_special ival 4 int4
8384
contrib_regression public test_special_id id 4 int4
85+
contrib_regression public test_special_primary id 4 int4
86+
contrib_regression public test_special_primary uniq 4 int4
87+
contrib_regression public test_special_primary_pkey id 4 int4
88+
contrib_regression public test_special_primary_uniq_key uniq 4 int4
8489
contrib_regression public test_special_ui ival 4 int4
8590
contrib_regression public testforeign c1 4 int4
8691
contrib_regression public testmatview id 4 int4
@@ -119,7 +124,31 @@ DECIMAL_DIGITS: SMALLINT(5) digits: 0, nullable
119124
PSEUDO_COLUMN: SMALLINT(5) digits: 0, nullable
120125
Result set:
121126
NULL xmin 4 xid 10 4 0 2
122-
Check for SQLSpecialColumns
127+
Check for SQLSpecialColumns primary key only public schema
128+
Result set metadata:
129+
SCOPE: LONGVARCHAR(8190) digits: 0, nullable
130+
COLUMN_NAME: VARCHAR(63) digits: 0, not nullable
131+
DATA_TYPE: VARCHAR(63) digits: 0, not nullable
132+
TYPE_NAME: VARCHAR(63) digits: 0, not nullable
133+
COLUMN_SIZE: SMALLINT(5) digits: 0, not nullable
134+
BUFFER_LENGTH: SMALLINT(5) digits: 0, not nullable
135+
DECIMAL_DIGITS: INTEGER(10) digits: 0, nullable
136+
PSEUDO_COLUMN: INTEGER(10) digits: 0, nullable
137+
Result set:
138+
NULL id int4 int4 4 4 0 1
139+
Check for SQLSpecialColumns primary key only no schema
140+
Result set metadata:
141+
SCOPE: LONGVARCHAR(8190) digits: 0, nullable
142+
COLUMN_NAME: VARCHAR(63) digits: 0, not nullable
143+
DATA_TYPE: VARCHAR(63) digits: 0, not nullable
144+
TYPE_NAME: VARCHAR(63) digits: 0, not nullable
145+
COLUMN_SIZE: SMALLINT(5) digits: 0, not nullable
146+
BUFFER_LENGTH: SMALLINT(5) digits: 0, not nullable
147+
DECIMAL_DIGITS: INTEGER(10) digits: 0, nullable
148+
PSEUDO_COLUMN: INTEGER(10) digits: 0, nullable
149+
Result set:
150+
NULL id int4 int4 4 4 0 1
151+
Check for SQLSpecialColumns unique index only
123152
Result set metadata:
124153
SCOPE: LONGVARCHAR(8190) digits: 0, nullable
125154
COLUMN_NAME: VARCHAR(63) digits: 0, not nullable

test/sampletables.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ INSERT INTO booltab VALUES (3, 'true', true);
3232
INSERT INTO booltab VALUES (4, 'false', false);
3333
INSERT INTO booltab VALUES (5, 'not', false);
3434

35+
CREATE TABLE test_special_primary(id integer primary key, uniq integer unique);
3536
CREATE TABLE test_special( id integer, ival integer);
3637
CREATE UNIQUE index test_special_id on public.test_special(id);
3738
CREATE UNIQUE index test_special_ui on public.test_special(ival);

test/src/catalogfunctions-test.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,45 @@ main(int argc, char **argv)
115115
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
116116
CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
117117

118+
/* Check for SQLSpecialColumns BEST_ROWID PRIMARY KEY in public schema */
119+
printf("Check for SQLSpecialColumns primary key only public schema\n");
120+
rc = SQLSpecialColumns(hstmt, SQL_BEST_ROWID,
121+
NULL, 0,
122+
(SQLCHAR *) "public", SQL_NTS,
123+
(SQLCHAR *) "test_special_primary", SQL_NTS,
124+
SQL_SCOPE_SESSION,
125+
SQL_NO_NULLS);
126+
CHECK_STMT_RESULT(rc, "SQLSpecialColumns primary key public schema failed", hstmt);
127+
128+
print_result_meta(hstmt);
129+
print_result(hstmt);
130+
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
131+
CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
132+
133+
/* Check for SQLSpecialColumns BEST_ROWID PRIMARY KEY no schema */
134+
printf("Check for SQLSpecialColumns primary key only no schema\n");
135+
rc = SQLSpecialColumns(hstmt, SQL_BEST_ROWID,
136+
NULL, 0,
137+
NULL, 0,
138+
(SQLCHAR *) "test_special_primary", SQL_NTS,
139+
SQL_SCOPE_SESSION,
140+
SQL_NO_NULLS);
141+
CHECK_STMT_RESULT(rc, "SQLSpecialColumns primary key no schema failed", hstmt);
142+
143+
print_result_meta(hstmt);
144+
print_result(hstmt);
145+
rc = SQLFreeStmt(hstmt, SQL_CLOSE);
146+
CHECK_STMT_RESULT(rc, "SQLFreeStmt failed", hstmt);
147+
118148
/* Check for SQLSpecialColumns BEST_ROWID */
119-
printf("Check for SQLSpecialColumns\n");
149+
printf("Check for SQLSpecialColumns unique index only\n");
120150
rc = SQLSpecialColumns(hstmt, SQL_BEST_ROWID,
121151
NULL, 0,
122152
(SQLCHAR *) "public", SQL_NTS,
123153
(SQLCHAR *) "test_special", SQL_NTS,
124154
SQL_SCOPE_SESSION,
125155
SQL_NO_NULLS);
126-
CHECK_STMT_RESULT(rc, "SQLSpecialColumns failed", hstmt);
156+
CHECK_STMT_RESULT(rc, "SQLSpecialColumns unique index public schema failed", hstmt);
127157

128158
print_result_meta(hstmt);
129159
print_result(hstmt);

0 commit comments

Comments
 (0)