!3234 解决分区键为表达式,功能正常,但 \d 查看表显示错误的问题

Merge pull request !3234 from 王修强/cherry-pick-1679405909
This commit is contained in:
opengauss-bot
2023-03-22 01:34:17 +00:00
committed by Gitee
3 changed files with 270 additions and 33 deletions

View File

@ -13,7 +13,6 @@
*/
#include "settings.h"
#include "postgres_fe.h"
#include <ctype.h>
#include "catalog/pg_class.h"
@ -1264,6 +1263,134 @@ static void PrintTableSliceInfo(char relKind, const char* distType, const char*
return;
}
uint32 GetVersionNum()
{
PQExpBufferData query;
initPQExpBuffer(&query);
PGresult* result = NULL;
int tuples = 0;
uint32 versionNum = 0;
appendPQExpBuffer(&query, "select pg_catalog.working_version_num()");
result = PSQLexec(query.data, false);
tuples = PQntuples(result);
if (tuples > 0)
versionNum = atooid(PQgetvalue(result, 0, 0));
PQclear(result);
termPQExpBuffer(&query);
return versionNum;
}
bool PartkeyexprIsNull(const char* relationname, bool isSubPart)
{
PQExpBufferData partkeyexpr;
PGresult* partkeyexpr_res = NULL;
int tuples = 0;
bool partkeyexprIsNull = true;
uint32 versionNum = GetVersionNum();
if (versionNum < 92836)
return partkeyexprIsNull;
initPQExpBuffer(&partkeyexpr);
if (!isSubPart)
appendPQExpBuffer(&partkeyexpr,
"select partkeyexpr from pg_partition where (parttype = 'r') and (parentid in (select oid from pg_class where relname = \'%s\'));",
relationname);
else
appendPQExpBuffer(&partkeyexpr,
"select distinct partkeyexpr from pg_partition where (parttype = 'p') and (parentid in (select oid from pg_class where relname = \'%s\'))",
relationname);
partkeyexpr_res = PSQLexec(partkeyexpr.data, false);
tuples = PQntuples(partkeyexpr_res);
char* partkeyexpr_buf = NULL;
if (tuples > 0)
partkeyexpr_buf = PQgetvalue(partkeyexpr_res, 0, 0);
if (partkeyexpr_buf && strcmp(partkeyexpr_buf, "") != 0)
partkeyexprIsNull = false;
PQclear(partkeyexpr_res);
termPQExpBuffer(&partkeyexpr);
return partkeyexprIsNull;
}
bool GetPartkeyexprSrc(bool isSubPart, const char* schemaname, const char* relationname, PQExpBuffer result_buf)
{
PQExpBufferData buf;
initPQExpBuffer(&buf);
PGresult* result = NULL;
int tuples = 0;
printfPQExpBuffer(&buf, "select pg_get_tabledef(\'\"%s\".\"%s\"\');", schemaname, relationname);
result = PSQLexec(buf.data, false);
tuples = PQntuples(result);
char* tabledef = NULL;
if (tuples > 0)
tabledef = PQgetvalue(result, 0, 0);
if (!tabledef) {
PQclear(result);
termPQExpBuffer(&buf);
return false;
}
char* start = NULL;
bool success = true;
if (isSubPart) {
start = strstr(tabledef, "SUBPARTITION BY");
if (!start) {
psql_error("Wrong table description: %s. The result is from SQL %s.", tabledef, buf.data);
success = false;
}
start += 16;
} else {
start = strstr(tabledef, "PARTITION BY");
if (!start) {
psql_error("Wrong table description: %s. The result is from SQL %s.", tabledef, buf.data);
success = false;
}
start += 13;
}
if (!success) {
PQclear(result);
termPQExpBuffer(&buf);
return false;
}
char* pos = strchr(start, '(');
if (!pos) {
psql_error("Wrong table description: %s. The result is from SQL %s.", tabledef, buf.data);
PQclear(result);
termPQExpBuffer(&buf);
return false;
}
char* i = strchr(start, ')');
char* j = strchr(pos + 1, '(');
size_t icount = 0;
size_t jcount = 0;
while (j && j < i) {
j++;
j = strchr(j, '(');
jcount++;
}
while (i && icount < jcount) {
i++;
i = strchr(i, ')');
icount++;
}
if (!i || (i < pos + 1)) {
psql_error("Wrong table description: %s. The result is from SQL %s.", tabledef, buf.data);
PQclear(result);
termPQExpBuffer(&buf);
return false;
}
appendBinaryPQExpBuffer(result_buf, pos + 1, i - pos - 1);
PQclear(result);
termPQExpBuffer(&buf);
return true;
}
/*
* describeOneTableDetails (for \d)
@ -2712,30 +2839,38 @@ static bool describeOneTableDetails(const char* schemaname, const char* relation
else if (strcmp(partition_type, "h") == 0)
printfPQExpBuffer(&tmp_part_buf, "Partition By HASH(");
/* 3. Get partition key name through partition key postition and pg_attribute. */
printfPQExpBuffer(&buf,
"SELECT attname\n"
"FROM pg_attribute\n"
"WHERE attrelid = '%s' AND attnum > 0 order by attnum",
oid);
bool partkeyexprIsNull = PartkeyexprIsNull(relationname, false);
if (!partkeyexprIsNull) {
bool success = GetPartkeyexprSrc(false, schemaname, relationname, &tmp_part_buf);
if (!success)
goto error_return;
} else {
printfPQExpBuffer(&buf,
"SELECT attname\n"
"FROM pg_attribute\n"
"WHERE attrelid = '%s' AND attnum > 0 order by attnum",
oid);
tmp_result = PSQLexec(buf.data, false);
if (tmp_result == NULL)
goto error_return;
tmp_result = PSQLexec(buf.data, false);
if (tmp_result == NULL)
goto error_return;
key_position = strtok_s(partition_key, separator_symbol, &next_key);
while (key_position != NULL) {
/*
* When there are multiple partition key, we use comma to separate them
* and show.
*/
if (!first_flag) {
appendPQExpBuffer(&tmp_part_buf, "%s", PQgetvalue(tmp_result, atoi(key_position) - 1, 0));
first_flag = true;
} else {
appendPQExpBuffer(&tmp_part_buf, ", %s", PQgetvalue(tmp_result, atoi(key_position) - 1, 0));
key_position = strtok_s(partition_key, separator_symbol, &next_key);
while (key_position != NULL) {
/*
* When there are multiple partition key, we use comma to separate them
* and show.
*/
if (!first_flag) {
appendPQExpBuffer(&tmp_part_buf, "%s", PQgetvalue(tmp_result, atoi(key_position) - 1, 0));
first_flag = true;
} else {
appendPQExpBuffer(&tmp_part_buf, ", %s", PQgetvalue(tmp_result, atoi(key_position) - 1, 0));
}
key_position = strtok_s(NULL, separator_symbol, &next_key);
}
key_position = strtok_s(NULL, separator_symbol, &next_key);
}
appendPQExpBuffer(&tmp_part_buf, ")");
if (strcmp(partition_type, "i") == 0) {
@ -2770,20 +2905,27 @@ static bool describeOneTableDetails(const char* schemaname, const char* relation
} else {
goto error_return;
}
char* subpartition_key = PQgetvalue(partresult, 0, 0);
char* next_subkey = NULL;
char* subkey_position = strtok_s(subpartition_key, separator_symbol, &next_subkey);
first_flag = false;
while (subkey_position != NULL) {
if (!first_flag) {
appendPQExpBuffer(&tmp_part_buf, "%s", PQgetvalue(tmp_result, atoi(subkey_position) - 1, 0));
first_flag = true;
} else {
appendPQExpBuffer(&tmp_part_buf, ", %s", PQgetvalue(tmp_result, atoi(subkey_position) - 1, 0));
bool subpartkeyexprIsNull = PartkeyexprIsNull(relationname, true);
if (!subpartkeyexprIsNull) {
bool success = GetPartkeyexprSrc(true, schemaname, relationname, &tmp_part_buf);
if (!success)
goto error_return;
} else {
char* subpartition_key = PQgetvalue(partresult, 0, 0);
char* next_subkey = NULL;
char* subkey_position = strtok_s(subpartition_key, separator_symbol, &next_subkey);
first_flag = false;
while (subkey_position != NULL) {
if (!first_flag) {
appendPQExpBuffer(&tmp_part_buf, "%s", PQgetvalue(tmp_result, atoi(subkey_position) - 1, 0));
first_flag = true;
} else {
appendPQExpBuffer(&tmp_part_buf, ", %s", PQgetvalue(tmp_result, atoi(subkey_position) - 1, 0));
}
subkey_position = strtok_s(NULL, separator_symbol, &next_subkey);
}
subkey_position = strtok_s(NULL, separator_symbol, &next_subkey);
}
appendPQExpBuffer(&tmp_part_buf, ")");
}

View File

@ -329,6 +329,19 @@ select pg_get_tabledef('testrangesubpart');
select pg_get_tabledef('testlistsubpart');
select pg_get_tabledef('testhashsubpart');
select pg_get_tabledef('testnormalsubpart');
\d testrangepart;
\d testlistpart;
\d testhashpart;
\d testrangesubpart;
\d testlistsubpart;
\d testhashsubpart;
\d testnormalsubpart;
create table "testrangesubPART"(a int, b int) partition by range(a-b) subpartition by range(a+b)
(
partition p0 values less than(1000)(subpartition p00 values less than(100)),
partition p1 values less than(2000)(subpartition p10 values less than(200))
);
\d "testrangesubPART"
create database part_expr_key_db1 dbcompatibility 'B';
\c part_expr_key_db1;
create table t1(c1 int not null, c2 int)

View File

@ -1109,6 +1109,88 @@ select pg_get_tabledef('testnormalsubpart');
ENABLE ROW MOVEMENT;
(1 row)
\d testrangepart;
Table "public.testrangepart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By RANGE(abs((a * 2)))
Number of partitions: 2 (View pg_partition to check each partition range.)
\d testlistpart;
Table "public.testlistpart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By LIST(abs((a * 2)))
Number of partitions: 2 (View pg_partition to check each partition range.)
\d testhashpart;
Table "public.testhashpart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By HASH(abs((a * 2)))
Number of partitions: 2 (View pg_partition to check each partition range.)
\d testrangesubpart;
Table "public.testrangesubpart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By RANGE((a + b)) Subpartition By RANGE((a - b))
Number of partitions: 2 (View pg_partition to check each partition range.)
Number of subpartitions: 2 (View pg_partition to check each subpartition range.)
\d testlistsubpart;
Table "public.testlistsubpart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By RANGE(abs((a * 2))) Subpartition By LIST(abs((b * 2)))
Number of partitions: 2 (View pg_partition to check each partition range.)
Number of subpartitions: 2 (View pg_partition to check each subpartition range.)
\d testhashsubpart;
Table "public.testhashsubpart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By RANGE(a) Subpartition By HASH(abs((b * 2)))
Number of partitions: 2 (View pg_partition to check each partition range.)
Number of subpartitions: 4 (View pg_partition to check each subpartition range.)
\d testnormalsubpart;
Table "public.testnormalsubpart"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By RANGE(a) Subpartition By RANGE(b)
Number of partitions: 2 (View pg_partition to check each partition range.)
Number of subpartitions: 2 (View pg_partition to check each subpartition range.)
create table "testrangesubPART"(a int, b int) partition by range(a-b) subpartition by range(a+b)
(
partition p0 values less than(1000)(subpartition p00 values less than(100)),
partition p1 values less than(2000)(subpartition p10 values less than(200))
);
\d "testrangesubPART"
Table "public.testrangesubPART"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Partition By RANGE((a - b)) Subpartition By RANGE((a + b))
Number of partitions: 2 (View pg_partition to check each partition range.)
Number of subpartitions: 2 (View pg_partition to check each subpartition range.)
create database part_expr_key_db1 dbcompatibility 'B';
\c part_expr_key_db1;
create table t1(c1 int not null, c2 int)