From 3384d09da28f3caa23326d0587e995010c8d38e2 Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Thu, 11 Oct 2012 14:45:54 +0300 Subject: [PATCH] Support for dropped fields --- Makefile | 2 +- src/plproxy.h | 1 + src/query.c | 4 +++ src/result.c | 44 +++++++++++---------------- src/type.c | 20 +++++++++++-- test/expected/plproxy_table.out | 53 +++++++++++++++++++++++++++++++++ test/sql/plproxy_table.sql | 44 +++++++++++++++++++++++++++ 7 files changed, 138 insertions(+), 30 deletions(-) create mode 100644 test/expected/plproxy_table.out create mode 100644 test/sql/plproxy_table.sql diff --git a/Makefile b/Makefile index 9f36f7b..7d89097 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ DISTNAME = $(EXTENSION)-$(DISTVERSION) # regression testing setup REGRESS = plproxy_init plproxy_test plproxy_select plproxy_many \ plproxy_errors plproxy_clustermap plproxy_dynamic_record \ - plproxy_encoding plproxy_split plproxy_target + plproxy_encoding plproxy_split plproxy_target plproxy_table REGRESS_OPTS = --dbname=regression --inputdir=test # pg9.1 ignores --dbname override CONTRIB_TESTDB := regression diff --git a/src/plproxy.h b/src/plproxy.h index ff06da8..fc6d9b6 100644 --- a/src/plproxy.h +++ b/src/plproxy.h @@ -296,6 +296,7 @@ typedef struct ProxyComposite TupleDesc tupdesc; /* Return tuple descriptor */ ProxyType **type_list; /* Column type info */ char **name_list; /* Quoted column names */ + int nfields; /* number of non-dropped fields */ bool use_binary; /* True if all columns support binary recv */ } ProxyComposite; diff --git a/src/query.c b/src/query.c index 78a7e53..d1c3e53 100644 --- a/src/query.c +++ b/src/query.c @@ -183,6 +183,8 @@ plproxy_standard_query(ProxyFunction *func, bool add_types) ProxyComposite *t = func->ret_composite; for (i = 0; i < t->tupdesc->natts; i++) { + if (t->tupdesc->attrs[i]->attisdropped) + continue; appendStringInfo(&sql, "%s%s::%s", ((i > 0) ? ", " : ""), t->name_list[i], @@ -217,6 +219,8 @@ plproxy_standard_query(ProxyFunction *func, bool add_types) appendStringInfo(&sql, " as ("); for (i = 0; i < t->tupdesc->natts; i++) { + if (t->tupdesc->attrs[i]->attisdropped) + continue; appendStringInfo(&sql, "%s%s %s", ((i > 0) ? ", " : ""), t->name_list[i], diff --git a/src/result.c b/src/result.c index 1b21e8b..e4df957 100644 --- a/src/result.c +++ b/src/result.c @@ -42,8 +42,9 @@ name_matches(ProxyFunction *func, const char *aname, PGresult *res, int col) static void map_results(ProxyFunction *func, PGresult *res) { - int i, - j, + int i, /* non-dropped column index */ + xi, /* tupdesc index */ + j, /* result column index */ natts, nfields = PQnfields(res); Form_pg_attribute a; @@ -58,21 +59,26 @@ map_results(ProxyFunction *func, PGresult *res) } natts = func->ret_composite->tupdesc->natts; - if (nfields < natts) + if (nfields < func->ret_composite->nfields) plproxy_error(func, "Got too few fields from remote end"); - if (nfields > natts) + if (nfields > func->ret_composite->nfields) plproxy_error(func, "Got too many fields from remote end"); - for (i = 0; i < natts; i++) + for (i = -1, xi = 0; xi < natts; xi++) { /* ->name_list has quoted names, take unquoted from ->tupdesc */ - a = func->ret_composite->tupdesc->attrs[i]; - aname = NameStr(a->attname); + a = func->ret_composite->tupdesc->attrs[xi]; + + func->result_map[xi] = -1; - func->result_map[i] = -1; + if (a->attisdropped) + continue; + i++; + + aname = NameStr(a->attname); if (name_matches(func, aname, res, i)) /* fast case: 1:1 mapping */ - func->result_map[i] = i; + func->result_map[xi] = i; else { /* slow case: messed up ordering */ @@ -87,28 +93,14 @@ map_results(ProxyFunction *func, PGresult *res) */ if (name_matches(func, aname, res, j)) { - func->result_map[i] = j; + func->result_map[xi] = j; break; } } } - if (func->result_map[i] < 0) + if (func->result_map[xi] < 0) plproxy_error(func, "Field %s does not exists in result", aname); - - /* oid sanity check. does not seem to work. */ - if (0) - { - Oid arg_oid = func->ret_composite->type_list[i]->type_oid; - Oid col_oid = PQftype(res, func->result_map[i]); - - if (arg_oid < 2000 || col_oid < 2000) - { - if (arg_oid != col_oid) - elog(WARNING, "oids do not match:%d/%d", - arg_oid, col_oid); - } - } } } @@ -157,7 +149,7 @@ return_composite(ProxyFunction *func, ProxyConnection *conn, FunctionCallInfo fc for (i = 0; i < meta->tupdesc->natts; i++) { col = func->result_map[i]; - if (PQgetisnull(conn->res, conn->pos, col)) + if (col < 0 || PQgetisnull(conn->res, conn->pos, col)) { values[i] = NULL; lengths[i] = 0; diff --git a/src/type.c b/src/type.c index 2360982..e091891 100644 --- a/src/type.c +++ b/src/type.c @@ -97,11 +97,17 @@ plproxy_composite_info(ProxyFunction *func, TupleDesc tupdesc) MemoryContextSwitchTo(old_ctx); + ret->nfields = 0; for (i = 0; i < natts; i++) { a = tupdesc->attrs[i]; if (a->attisdropped) - plproxy_error(func, "dropped attrs not supported"); + { + ret->name_list[i] = NULL; + ret->type_list[i] = NULL; + continue; + } + ret->nfields++; name = quote_identifier(NameStr(a->attname)); ret->name_list[i] = plproxy_func_strdup(func, name); @@ -125,7 +131,8 @@ plproxy_free_composite(ProxyComposite *rec) for (i = 0; i < natts; i++) { plproxy_free_type(rec->type_list[i]); - pfree(rec->name_list[i]); + if (rec->name_list[i]) + pfree(rec->name_list[i]); } pfree(rec->type_list); pfree(rec->name_list); @@ -136,6 +143,9 @@ plproxy_free_composite(ProxyComposite *rec) void plproxy_free_type(ProxyType *type) { + if (type == NULL) + return; + if (type->name) pfree(type->name); @@ -169,7 +179,11 @@ plproxy_recv_composite(ProxyComposite *meta, char **values, int *lengths, int *f for (i = 0; i < natts; i++) { if (tupdesc->attrs[i]->attisdropped) - elog(ERROR, "dropped attrs not supported"); + { + dvalues[i] = (Datum)NULL; + nulls[i] = 'n'; + continue; + } dvalues[i] = plproxy_recv_type(meta->type_list[i], values[i], lengths[i], fmts[i]); diff --git a/test/expected/plproxy_table.out b/test/expected/plproxy_table.out new file mode 100644 index 0000000..6774a5f --- /dev/null +++ b/test/expected/plproxy_table.out @@ -0,0 +1,53 @@ +\c test_part0 +create function test_table1(out id int4, out data text, out data2 text, out data3 text) +as $$ +begin + id = 1; + data = 'Data1'; + data2 = 'Data2'; + data3 = 'Data3'; + return; +end; +$$ language plpgsql; +select * from test_table1(); + id | data | data2 | data3 +----+-------+-------+------- + 1 | Data1 | Data2 | Data3 +(1 row) + +\c regression +create table ret_table ( + id int4, + data text +); +create function test_table1() +returns ret_table as $$ + cluster 'testcluster'; + run on 0; +$$ language plproxy; +select * from test_table1(); + id | data +----+------- + 1 | Data1 +(1 row) + +-- add column +alter table ret_table add column data2 text; +--select * from test_table1(); -- invalidate does not work +\c regression +select * from test_table1(); + id | data | data2 +----+-------+------- + 1 | Data1 | Data2 +(1 row) + +-- drop & add +alter table ret_table drop column data2; +alter table ret_table add column data3 text; +\c regression +select * from test_table1(); + id | data | data3 +----+-------+------- + 1 | Data1 | Data3 +(1 row) + diff --git a/test/sql/plproxy_table.sql b/test/sql/plproxy_table.sql new file mode 100644 index 0000000..2be6691 --- /dev/null +++ b/test/sql/plproxy_table.sql @@ -0,0 +1,44 @@ + +\c test_part0 + +create function test_table1(out id int4, out data text, out data2 text, out data3 text) +as $$ +begin + id = 1; + data = 'Data1'; + data2 = 'Data2'; + data3 = 'Data3'; + return; +end; +$$ language plpgsql; + +select * from test_table1(); + +\c regression +create table ret_table ( + id int4, + data text +); + +create function test_table1() +returns ret_table as $$ + cluster 'testcluster'; + run on 0; +$$ language plproxy; + +select * from test_table1(); + + +-- add column +alter table ret_table add column data2 text; +--select * from test_table1(); -- invalidate does not work +\c regression +select * from test_table1(); + +-- drop & add +alter table ret_table drop column data2; +alter table ret_table add column data3 text; +\c regression +select * from test_table1(); + + -- 2.39.5