Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb78a396

Browse files
committed
Merge branch 'PGPRO-4549'
2 parentsbb06f2c +720adc8 commitb78a396

File tree

7 files changed

+220
-19
lines changed

7 files changed

+220
-19
lines changed

‎expected/pg_variables.out

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -773,8 +773,8 @@ CLOSE r1_cur;
773773
COMMIT; -- warning
774774
RESET client_min_messages;
775775
-- Clean memory after unsuccessful creation of a variable
776-
SELECT pgv_insert('vars4', 'r1', row('str1', 'str1')); -- fail
777-
ERROR: could not identify a hash function for typeunknown
776+
SELECT pgv_insert('vars4', 'r1', row (('str1'::text, 'str1'::text))); -- fail
777+
ERROR: could not identify a hash function for typerecord
778778
SELECT package FROM pgv_stats() WHERE package = 'vars4';
779779
package
780780
---------
@@ -954,28 +954,32 @@ SELECT pgv_select('vars', 'r1');
954954
(1,str1,str2)
955955
(1 row)
956956

957-
SELECT pgv_insert('vars', 'r2', row(1, 'str1'));
957+
SELECT pgv_insert('vars', 'r2', row(1, 'str1')); -- ok, UNKNOWNOID of 'str1' converts to TEXTOID
958+
pgv_insert
959+
------------
960+
961+
(1 row)
962+
963+
SELECT pgv_insert('vars', 'r2', foo) FROM foo; -- ok
958964
pgv_insert
959965
------------
960966

961967
(1 row)
962968

963-
SELECT pgv_insert('vars', 'r2', foo) FROM foo;
964-
ERROR: new record attribute type for attribute number 2 differs from variable "r2" structure.
965-
HINT: You may need explicit type casts.
966969
SELECT pgv_select('vars', 'r2');
967970
pgv_select
968971
------------
969972
(1,str1)
970-
(1 row)
973+
(0,str00)
974+
(2 rows)
971975

972976
SELECT pgv_insert('vars', 'r3', row(1, 'str1'::text));
973977
pgv_insert
974978
------------
975979

976980
(1 row)
977981

978-
SELECT pgv_insert('vars', 'r3', foo) FROM foo;
982+
SELECT pgv_insert('vars', 'r3', foo) FROM foo; -- ok, no conversions
979983
pgv_insert
980984
------------
981985

@@ -988,3 +992,37 @@ SELECT pgv_select('vars', 'r3');
988992
(0,str00)
989993
(2 rows)
990994

995+
SELECT pgv_insert('vars', 'r4', row(1, 2::int));
996+
pgv_insert
997+
------------
998+
999+
(1 row)
1000+
1001+
SELECT pgv_insert('vars', 'r4', row(0, 'str1')); -- fail, UNKNOWNOID of 'str1' can't be converted to int
1002+
ERROR: new record attribute type for attribute number 2 differs from variable "r4" structure.
1003+
HINT: You may need explicit type casts.
1004+
SELECT pgv_select('vars', 'r4');
1005+
pgv_select
1006+
------------
1007+
(1,2)
1008+
(1 row)
1009+
1010+
SELECT pgv_insert('vars', 'r5', foo) FROM foo; -- types: int, text
1011+
pgv_insert
1012+
------------
1013+
1014+
(1 row)
1015+
1016+
SELECT pgv_insert('vars', 'r5', row(1, 'str1')); -- ok, UNKNOWNOID of 'str1' converts to TEXTOID
1017+
pgv_insert
1018+
------------
1019+
1020+
(1 row)
1021+
1022+
SELECT pgv_select('vars', 'r5');
1023+
pgv_select
1024+
------------
1025+
(1,str1)
1026+
(0,str00)
1027+
(2 rows)
1028+

‎expected/pg_variables_trans.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,8 +1858,8 @@ SELECT pgv_insert('package', 'errs',row(1), true);
18581858
(1 row)
18591859

18601860
-- Variable should not exists in case when error occurs during creation
1861-
SELECT pgv_insert('vars4', 'r1', row('str1', 'str1'));
1862-
ERROR: could not identify a hash function for typeunknown
1861+
SELECT pgv_insert('vars4', 'r1', row (('str1'::text, 'str1'::text)));
1862+
ERROR: could not identify a hash function for typerecord
18631863
SELECT pgv_select('vars4', 'r1', 0);
18641864
ERROR: unrecognized package "vars4"
18651865
-- If variable created and removed in same transaction level,

‎pg_variables.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ do { \
119119
} while(0)
120120
#endif/* PG_VERSION_NUM */
121121

122+
/* User controlled GUCs */
123+
boolconvert_unknownoid_guc;
124+
boolconvert_unknownoid;
125+
122126
staticHTAB*packagesHash=NULL;
123127
staticMemoryContextModuleContext=NULL;
124128

@@ -773,6 +777,14 @@ variable_insert(PG_FUNCTION_ARGS)
773777
/*
774778
* This is the first record for the var_name. Initialize record.
775779
*/
780+
/* Convert UNKNOWNOID to TEXTOID if needed
781+
* tupdesc may be changed
782+
*/
783+
if (convert_unknownoid)
784+
{
785+
coerce_unknown_first_record(&tupdesc,&rec);
786+
}
787+
776788
init_record(record,tupdesc,variable);
777789
variable->is_deleted= false;
778790
}
@@ -781,8 +793,11 @@ variable_insert(PG_FUNCTION_ARGS)
781793
/*
782794
* We need to check attributes of the new row if this is a transient
783795
* record type or if last record has different id.
796+
* Also we convert UNKNOWNOID to TEXTOID if needed.
797+
* tupdesc may be changed
784798
*/
785-
check_attributes(variable,tupdesc);
799+
check_attributes(variable,&rec,tupdesc);
800+
786801
}
787802

788803
insert_record(variable,rec);
@@ -863,7 +878,11 @@ variable_update(PG_FUNCTION_ARGS)
863878
tupTypmod=HeapTupleHeaderGetTypMod(rec);
864879

865880
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
866-
check_attributes(variable,tupdesc);
881+
/*
882+
* Convert UNKNOWNOID to TEXTOID if needed
883+
* tupdesc may be changed
884+
*/
885+
check_attributes(variable,&rec,tupdesc);
867886
ReleaseTupleDesc(tupdesc);
868887

869888
res=update_record(variable,rec);
@@ -2921,6 +2940,17 @@ freeStatsLists(void)
29212940
void
29222941
_PG_init(void)
29232942
{
2943+
DefineCustomBoolVariable("pg_variables.convert_unknownoid",
2944+
"Use \'TEXT\' format for all values of \'UNKNOWNOID\', default is true.",
2945+
NULL,
2946+
&convert_unknownoid,
2947+
true,
2948+
PGC_USERSET,
2949+
0,/* FLAGS??? */
2950+
NULL,
2951+
NULL,
2952+
NULL);
2953+
29242954
RegisterXactCallback(pgvTransCallback,NULL);
29252955
RegisterSubXactCallback(pgvSubTransCallback,NULL);
29262956

‎pg_variables.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include"access/tupdesc.h"
1717
#include"datatype/timestamp.h"
1818
#include"utils/date.h"
19+
#include"utils/guc.h"
1920
#include"utils/hsearch.h"
2021
#include"utils/numeric.h"
2122
#include"utils/jsonb.h"
@@ -179,8 +180,12 @@ typedef struct ChangesStackNode
179180
MemoryContextctx;
180181
}ChangesStackNode;
181182

183+
/* pg_variables.c */
184+
externboolconvert_unknownoid;
185+
182186
externvoidinit_record(RecordVar*record,TupleDesctupdesc,Variable*variable);
183-
externvoidcheck_attributes(Variable*variable,TupleDesctupdesc);
187+
externvoidcheck_attributes(Variable*variable,HeapTupleHeader*rec,TupleDesctupdesc);
188+
externvoidcoerce_unknown_first_record(TupleDesc*tupdesc,HeapTupleHeader*rec);
184189
externvoidcheck_record_key(Variable*variable,Oidtypid);
185190

186191
externvoidinsert_record(Variable*variable,HeapTupleHeadertupleHeader);

‎pg_variables_record.c

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525

2626
#include"catalog/pg_collation.h"
2727
#include"catalog/pg_type.h"
28+
#include"parser/parse_type.h"
2829
#include"utils/builtins.h"
2930
#include"utils/datum.h"
31+
#include"utils/lsyscache.h"
32+
#include"utils/syscache.h"
3033
#include"utils/memutils.h"
3134
#include"utils/typcache.h"
3235

@@ -172,14 +175,118 @@ init_record(RecordVar *record, TupleDesc tupdesc, Variable *variable)
172175
MemoryContextSwitchTo(oldcxt);
173176
}
174177

178+
/* Check if any attributes of type UNKNOWNOID are in given tupdesc */
179+
staticint
180+
is_unknownoid_in_tupdesc(TupleDesctupdesc)
181+
{
182+
inti=0;
183+
for (i=0;i<tupdesc->natts;i++)
184+
{
185+
Form_pg_attributeattr=GetTupleDescAttr(tupdesc,i);
186+
187+
if (attr->atttypid==UNKNOWNOID)
188+
return true;
189+
190+
}
191+
return false;
192+
}
193+
194+
/* Replace all attributes of type UNKNOWNOID to TEXTOID in given tupdesc */
195+
staticvoid
196+
coerce_unknown_rewrite_tupdesc(TupleDescold_tupdesc,TupleDesc*return_tupdesc)
197+
{
198+
inti;
199+
200+
(*return_tupdesc)=CreateTupleDescCopy(old_tupdesc);
201+
202+
for (i=0;i<old_tupdesc->natts;i++)
203+
{
204+
Form_pg_attributeattr=GetTupleDescAttr(old_tupdesc,i);
205+
206+
if (attr->atttypid==UNKNOWNOID)
207+
{
208+
FormData_pg_attributenew_attr=*attr;
209+
210+
new_attr.atttypid=TEXTOID;
211+
new_attr.attlen=-1;
212+
new_attr.atttypmod=-1;
213+
memcpy(TupleDescAttr((*return_tupdesc),i),&new_attr,sizeof(FormData_pg_attribute));
214+
}
215+
}
216+
}
217+
218+
/*
219+
* Deform tuple with old_tupdesc, coerce values of type UNKNOWNOID to TEXTOID, form tuple with new_tupdesc.
220+
* new_tupdesc must have the same attributes as old_tupdesc except such of types UNKNOWNOID -- they must be of TEXTOID type
221+
*/
222+
staticvoid
223+
reconstruct_tuple(TupleDescold_tupdesc,TupleDescnew_tupdesc,HeapTupleHeader*rec)
224+
{
225+
HeapTupleDatatuple;
226+
HeapTuplenewtup;
227+
Datum*values= (Datum*)palloc(old_tupdesc->natts*sizeof(Datum));
228+
bool*isnull= (bool*)palloc(old_tupdesc->natts*sizeof(bool));
229+
OidbaseTypeId=UNKNOWNOID;
230+
int32baseTypeMod=-1;
231+
int32inputTypeMod=-1;
232+
TypebaseType=NULL;
233+
inti;
234+
235+
baseTypeId=getBaseTypeAndTypmod(TEXTOID,&baseTypeMod);
236+
baseType=typeidType(baseTypeId);
237+
/* Build a temporary HeapTuple control structure */
238+
tuple.t_len=HeapTupleHeaderGetDatumLength(*rec);
239+
tuple.t_data=*rec;
240+
heap_deform_tuple(&tuple,old_tupdesc,values,isnull);
241+
242+
for (i=0;i<old_tupdesc->natts;i++)
243+
{
244+
Form_pg_attributeattr=GetTupleDescAttr(old_tupdesc,i);
245+
246+
if (attr->atttypid==UNKNOWNOID)
247+
{
248+
values[i]=stringTypeDatum(baseType,
249+
DatumGetCString(values[i]),
250+
inputTypeMod);
251+
}
252+
}
253+
254+
newtup=heap_form_tuple(new_tupdesc,values,isnull);
255+
(*rec)=newtup->t_data;
256+
pfree(isnull);
257+
pfree(values);
258+
ReleaseSysCache(baseType);
259+
}
260+
261+
/*
262+
* Used in pg_variables.c insert_record for coercing types in first record in variable.
263+
* If there are UNKNOWNOIDs in tupdesc, rewrites it and reconstructs tuple with new tupdesc.
264+
* Replaces given tupdesc with the new one.
265+
*/
266+
void
267+
coerce_unknown_first_record(TupleDesc*tupdesc,HeapTupleHeader*rec)
268+
{
269+
TupleDescnew_tupdesc=NULL;
270+
271+
if (!is_unknownoid_in_tupdesc(*tupdesc))
272+
return;
273+
274+
coerce_unknown_rewrite_tupdesc(*tupdesc,&new_tupdesc);
275+
reconstruct_tuple(*tupdesc,new_tupdesc,rec);
276+
277+
ReleaseTupleDesc(*tupdesc);
278+
(*tupdesc)=new_tupdesc;
279+
}
280+
175281
/*
176282
* New record structure should be the same as the first record.
177283
*/
178284
void
179-
check_attributes(Variable*variable,TupleDesctupdesc)
285+
check_attributes(Variable*variable,HeapTupleHeader*rec,TupleDesctupdesc)
180286
{
181287
inti;
182288
RecordVar*record;
289+
boolunknowns= false;
183290

184291
Assert(variable->typid==RECORDOID);
185292

@@ -198,6 +305,16 @@ check_attributes(Variable *variable, TupleDesc tupdesc)
198305
Form_pg_attributeattr1=GetTupleDescAttr(record->tupdesc,i),
199306
attr2=GetTupleDescAttr(tupdesc,i);
200307

308+
/*
309+
* For the sake of convenience, we consider all the unknown types are to be
310+
* a text type.
311+
*/
312+
if (convert_unknownoid&& (attr1->atttypid==TEXTOID)&& (attr2->atttypid==UNKNOWNOID))
313+
{
314+
unknowns= true;
315+
continue;
316+
}
317+
201318
if ((attr1->atttypid!=attr2->atttypid)
202319
|| (attr1->attndims!=attr2->attndims)
203320
|| (attr1->atttypmod!=attr2->atttypmod))
@@ -208,6 +325,9 @@ check_attributes(Variable *variable, TupleDesc tupdesc)
208325
i+1,GetName(variable)),
209326
errhint("You may need explicit type casts.")));
210327
}
328+
329+
if (unknowns)
330+
reconstruct_tuple(tupdesc,record->tupdesc,rec);
211331
}
212332

213333
/*

‎sql/pg_variables.sql

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ COMMIT; -- warning
222222
RESET client_min_messages;
223223

224224
-- Clean memory after unsuccessful creation of a variable
225-
SELECT pgv_insert('vars4','r1', row('str1','str1'));-- fail
225+
SELECT pgv_insert('vars4','r1', row (('str1'::text,'str1'::text)));-- fail
226226
SELECT packageFROM pgv_stats()WHERE package='vars4';
227227

228228
-- Remove package if it is empty
@@ -268,10 +268,18 @@ SELECT pgv_select('vars', 'r1');
268268
SELECT pgv_insert('vars','r1', foo)FROM foo;
269269
SELECT pgv_select('vars','r1');
270270

271-
SELECT pgv_insert('vars','r2', row(1,'str1'));
272-
SELECT pgv_insert('vars','r2', foo)FROM foo;
271+
SELECT pgv_insert('vars','r2', row(1,'str1'));-- ok, UNKNOWNOID of 'str1' converts to TEXTOID
272+
SELECT pgv_insert('vars','r2', foo)FROM foo;-- ok
273273
SELECT pgv_select('vars','r2');
274274

275275
SELECT pgv_insert('vars','r3', row(1,'str1'::text));
276-
SELECT pgv_insert('vars','r3', foo)FROM foo;
276+
SELECT pgv_insert('vars','r3', foo)FROM foo;-- ok, no conversions
277277
SELECT pgv_select('vars','r3');
278+
279+
SELECT pgv_insert('vars','r4', row(1,2::int));
280+
SELECT pgv_insert('vars','r4', row(0,'str1'));-- fail, UNKNOWNOID of 'str1' can't be converted to int
281+
SELECT pgv_select('vars','r4');
282+
283+
SELECT pgv_insert('vars','r5', foo)FROM foo;-- types: int, text
284+
SELECT pgv_insert('vars','r5', row(1,'str1'));-- ok, UNKNOWNOID of 'str1' converts to TEXTOID
285+
SELECT pgv_select('vars','r5');

‎sql/pg_variables_trans.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ FROM generate_series(1,5) AS gs(n) WHERE 1.0/(n-3)<>0;
470470
SELECT pgv_insert('package','errs',row(1), true);
471471

472472
-- Variable should not exists in case when error occurs during creation
473-
SELECT pgv_insert('vars4','r1', row('str1','str1'));
473+
SELECT pgv_insert('vars4','r1', row (('str1'::text,'str1'::text)));
474474
SELECT pgv_select('vars4','r1',0);
475475

476476
-- If variable created and removed in same transaction level,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp