!3234 解决分区键为表达式,功能正常,但 \d 查看表显示错误的问题
Merge pull request !3234 from 王修强/cherry-pick-1679405909
This commit is contained in:
@ -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, ")");
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user