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

Commit649bf07

Browse files
committed
Merge branch 'master' into stable
2 parents13afa3f +dd9f391 commit649bf07

File tree

7 files changed

+137
-26
lines changed

7 files changed

+137
-26
lines changed

‎expected/pg_variables.out

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,20 @@ SELECT pgv_insert('vars3', 'r1', row(1, 1));
553553
ERROR: new record structure differs from variable "r1" structure
554554
SELECT pgv_insert('vars3', 'r1', row('str1', 'str1'));
555555
ERROR: new record structure differs from variable "r1" structure
556+
SELECT pgv_select('vars3', 'r1') LIMIT 2;
557+
pgv_select
558+
------------
559+
(,strNULL)
560+
(1,str11)
561+
(2 rows)
562+
563+
SELECT pgv_select('vars3', 'r1') LIMIT 2 OFFSET 2;
564+
pgv_select
565+
------------
566+
(2,)
567+
(0,str00)
568+
(2 rows)
569+
556570
SELECT pgv_select('vars3', 'r1');
557571
pgv_select
558572
------------

‎expected/pg_variables_trans.out

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,11 @@ SELECT pgv_insert('package', 'errs',row(1), true);
18541854

18551855
(1 row)
18561856

1857+
-- Variable should not exists in case when error occurs during creation
1858+
SELECT pgv_insert('vars4', 'r1', row('str1', 'str1'));
1859+
ERROR: could not identify a hash function for type unknown
1860+
SELECT pgv_select('vars4', 'r1', 0);
1861+
ERROR: unrecognized variable "r1"
18571862
SELECT pgv_free();
18581863
pgv_free
18591864
----------

‎pg_variables.c

Lines changed: 98 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static Variable *createVariableInternal(Package *package,
5757
text*name,Oidtypid,
5858
boolis_transactional);
5959
staticvoidremovePackageInternal(Package*package);
60+
staticvoidresetVariablesCache(boolwith_package);
6061

6162
/* Functions to work with transactional objects */
6263
staticvoidcreateSavepoint(TransObject*object,TransObjectTypetype);
@@ -67,7 +68,6 @@ static void copyValue(VarState *src, VarState *dest, Variable *destVar);
6768
staticvoidfreeValue(VarState*varstate,Oidtypid);
6869
staticvoidremoveState(TransObject*object,TransObjectTypetype,
6970
TransState*stateToDelete);
70-
staticvoidremoveObject(TransObject*object,TransObjectTypetype);
7171
staticboolisObjectChangedInCurrentTrans(TransObject*object);
7272
staticboolisObjectChangedInUpperTrans(TransObject*object);
7373

@@ -80,6 +80,9 @@ static void makePackHTAB(Package *package, bool is_trans);
8080
staticinlineChangedObject*makeChangedObject(TransObject*object,
8181
MemoryContextctx);
8282

83+
/* Hook functions */
84+
staticvoidvariable_ExecutorEnd(QueryDesc*queryDesc);
85+
8386
#defineCHECK_ARGS_FOR_NULL() \
8487
do { \
8588
if (fcinfo->argnull[0]) \
@@ -99,7 +102,19 @@ static MemoryContext ModuleContext = NULL;
99102
staticPackage*LastPackage=NULL;
100103
/* Recent variable */
101104
staticVariable*LastVariable=NULL;
105+
/* Recent row type id */
106+
staticOidLastTypeId=InvalidOid;
107+
108+
/*
109+
* Cache sequentially search through hash table status. It is necessary for
110+
* clean up if hash_seq_term() wasn't called or if we didn't scan the whole
111+
* table. In this case we need to manually call hash_seq_term() within
112+
* variable_ExecutorEnd().
113+
*/
114+
staticHASH_SEQ_STATUS*LastHSeqStatus=NULL;
102115

116+
/* Saved hook values for recall */
117+
staticExecutorEnd_hook_typeprev_ExecutorEnd=NULL;
103118

104119
/* This stack contains lists of changed variables and packages per each subxact level */
105120
staticdlist_head*changesStack=NULL;
@@ -291,7 +306,7 @@ variable_insert(PG_FUNCTION_ARGS)
291306

292307
OidtupType;
293308
int32tupTypmod;
294-
TupleDesctupdesc;
309+
TupleDesctupdesc=NULL;
295310
RecordVar*record;
296311

297312
/* Checks */
@@ -360,23 +375,34 @@ variable_insert(PG_FUNCTION_ARGS)
360375
/* Insert a record */
361376
tupType=HeapTupleHeaderGetTypeId(rec);
362377
tupTypmod=HeapTupleHeaderGetTypMod(rec);
363-
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
364378

365379
record=&(GetActualValue(variable).record);
366380
if (!record->tupdesc)
367381
{
368382
/*
369383
* This is the first record for the var_name. Initialize record.
370384
*/
385+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
371386
init_record(record,tupdesc,variable);
372387
}
373-
else
388+
elseif (LastTypeId==RECORDOID|| !OidIsValid(LastTypeId)||
389+
LastTypeId!=tupType)
390+
{
391+
/*
392+
* We need to check attributes of the new row if this is a transient
393+
* record type or if last record has different id.
394+
*/
395+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
374396
check_attributes(variable,tupdesc);
397+
}
398+
399+
LastTypeId=tupType;
375400

376401
insert_record(variable,rec);
377402

378403
/* Release resources */
379-
ReleaseTupleDesc(tupdesc);
404+
if (tupdesc)
405+
ReleaseTupleDesc(tupdesc);
380406

381407
PG_FREE_IF_COPY(package_name,0);
382408
PG_FREE_IF_COPY(var_name,1);
@@ -396,7 +422,6 @@ variable_update(PG_FUNCTION_ARGS)
396422
boolres;
397423
OidtupType;
398424
int32tupTypmod;
399-
TupleDesctupdesc;
400425

401426
/* Checks */
402427
CHECK_ARGS_FOR_NULL();
@@ -447,14 +472,22 @@ variable_update(PG_FUNCTION_ARGS)
447472
/* Update a record */
448473
tupType=HeapTupleHeaderGetTypeId(rec);
449474
tupTypmod=HeapTupleHeaderGetTypMod(rec);
450-
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
451475

452-
check_attributes(variable,tupdesc);
476+
if (LastTypeId==RECORDOID|| !OidIsValid(LastTypeId)||
477+
LastTypeId!=tupType)
478+
{
479+
TupleDesctupdesc=NULL;
480+
481+
tupdesc=lookup_rowtype_tupdesc(tupType,tupTypmod);
482+
check_attributes(variable,tupdesc);
483+
ReleaseTupleDesc(tupdesc);
484+
}
485+
486+
LastTypeId=tupType;
487+
453488
res=update_record(variable,rec);
454489

455490
/* Release resources */
456-
ReleaseTupleDesc(tupdesc);
457-
458491
PG_FREE_IF_COPY(package_name,0);
459492
PG_FREE_IF_COPY(var_name,1);
460493

@@ -575,6 +608,8 @@ variable_select(PG_FUNCTION_ARGS)
575608
MemoryContextSwitchTo(oldcontext);
576609
PG_FREE_IF_COPY(package_name,0);
577610
PG_FREE_IF_COPY(var_name,1);
611+
612+
LastHSeqStatus=rstat;
578613
}
579614

580615
funcctx=SRF_PERCALL_SETUP();
@@ -592,6 +627,7 @@ variable_select(PG_FUNCTION_ARGS)
592627
}
593628
else
594629
{
630+
LastHSeqStatus=NULL;
595631
pfree(rstat);
596632
SRF_RETURN_DONE(funcctx);
597633
}
@@ -867,8 +903,7 @@ remove_variable(PG_FUNCTION_ARGS)
867903
GetActualState(variable)->is_valid= false;
868904
}
869905

870-
/* Remove variable from cache */
871-
LastVariable=NULL;
906+
resetVariablesCache(false);
872907

873908
PG_FREE_IF_COPY(package_name,0);
874909
PG_FREE_IF_COPY(var_name,1);
@@ -904,9 +939,7 @@ remove_package(PG_FUNCTION_ARGS)
904939
errmsg("unrecognized package \"%s\"",key)));
905940
}
906941

907-
/* Remove package and variable from cache */
908-
LastPackage=NULL;
909-
LastVariable=NULL;
942+
resetVariablesCache(true);
910943

911944
PG_FREE_IF_COPY(package_name,0);
912945
PG_RETURN_VOID();
@@ -934,6 +967,20 @@ removePackageInternal(Package *package)
934967
GetActualState(package)->is_valid= false;
935968
}
936969

970+
/*
971+
* Reset cache variables to their default values. It is necessary to do in case
972+
* of some changes: removing, rollbacking, etc.
973+
*/
974+
staticvoid
975+
resetVariablesCache(boolwith_package)
976+
{
977+
/* Remove package and variable from cache */
978+
if (with_package)
979+
LastPackage=NULL;
980+
LastVariable=NULL;
981+
LastTypeId=InvalidOid;
982+
}
983+
937984
/*
938985
* Remove all packages and variables.
939986
* Memory context will be released after committing.
@@ -955,9 +1002,7 @@ remove_packages(PG_FUNCTION_ARGS)
9551002
removePackageInternal(package);
9561003
}
9571004

958-
/* Remove package and variable from cache */
959-
LastPackage=NULL;
960-
LastVariable=NULL;
1005+
resetVariablesCache(true);
9611006

9621007
PG_RETURN_VOID();
9631008
}
@@ -1157,6 +1202,8 @@ get_packages_stats(PG_FUNCTION_ARGS)
11571202
hash_seq_init(pstat,packagesHash);
11581203

11591204
funcctx->user_fctx=pstat;
1205+
1206+
LastHSeqStatus=pstat;
11601207
}
11611208
else
11621209
funcctx->user_fctx=NULL;
@@ -1202,6 +1249,7 @@ get_packages_stats(PG_FUNCTION_ARGS)
12021249
}
12031250
else
12041251
{
1252+
LastHSeqStatus=NULL;
12051253
pfree(pstat);
12061254
SRF_RETURN_DONE(funcctx);
12071255
}
@@ -1577,13 +1625,14 @@ copyValue(VarState *src, VarState *dest, Variable *destVar)
15771625
staticvoid
15781626
freeValue(VarState*varstate,Oidtypid)
15791627
{
1580-
if (typid==RECORDOID)
1628+
if (typid==RECORDOID&&varstate->value.record.hctx)
15811629
{
15821630
/* All records will be freed */
15831631
MemoryContextDelete(varstate->value.record.hctx);
15841632
}
15851633
elseif (varstate->value.scalar.typbyval== false&&
1586-
varstate->value.scalar.is_null== false)
1634+
varstate->value.scalar.is_null== false&&
1635+
varstate->value.scalar.value)
15871636
{
15881637
pfree(DatumGetPointer(varstate->value.scalar.value));
15891638
}
@@ -1602,7 +1651,8 @@ removeState(TransObject *object, TransObjectType type, TransState *stateToDelete
16021651
pfree(stateToDelete);
16031652
}
16041653

1605-
staticvoid
1654+
/* Remove package or variable (either transactional or regular) */
1655+
void
16061656
removeObject(TransObject*object,TransObjectTypetype)
16071657
{
16081658
boolfound;
@@ -1623,7 +1673,9 @@ removeObject(TransObject *object, TransObjectType type)
16231673
hash=packagesHash;
16241674
}
16251675
else
1626-
hash= ((Variable*)object)->package->varHashTransact;
1676+
hash= ((Variable*)object)->is_transactional ?
1677+
((Variable*)object)->package->varHashTransact :
1678+
((Variable*)object)->package->varHashRegular;
16271679

16281680
/* Remove all object's states */
16291681
while (!dlist_is_empty(&object->states))
@@ -1632,8 +1684,7 @@ removeObject(TransObject *object, TransObjectType type)
16321684
/* Remove object from hash table */
16331685
hash_search(hash,object->name,HASH_REMOVE,&found);
16341686

1635-
LastPackage=NULL;
1636-
LastVariable=NULL;
1687+
resetVariablesCache(true);
16371688
}
16381689

16391690
/*
@@ -2004,8 +2055,7 @@ processChanges(Action action)
20042055
MemoryContextDelete(ModuleContext);
20052056
packagesHash=NULL;
20062057
ModuleContext=NULL;
2007-
LastPackage=NULL;
2008-
LastVariable=NULL;
2058+
resetVariablesCache(true);
20092059
changesStack=NULL;
20102060
changesStackContext=NULL;
20112061
}
@@ -2065,6 +2115,23 @@ pgvTransCallback(XactEvent event, void *arg)
20652115
}
20662116
}
20672117

2118+
/*
2119+
* ExecutorEnd hook: clean up hash table sequential scan status
2120+
*/
2121+
staticvoid
2122+
variable_ExecutorEnd(QueryDesc*queryDesc)
2123+
{
2124+
if (LastHSeqStatus)
2125+
{
2126+
hash_seq_term(LastHSeqStatus);
2127+
LastHSeqStatus=NULL;
2128+
}
2129+
if (prev_ExecutorEnd)
2130+
prev_ExecutorEnd(queryDesc);
2131+
else
2132+
standard_ExecutorEnd(queryDesc);
2133+
}
2134+
20682135
/*
20692136
* Register callback function when module starts
20702137
*/
@@ -2073,6 +2140,10 @@ _PG_init(void)
20732140
{
20742141
RegisterXactCallback(pgvTransCallback,NULL);
20752142
RegisterSubXactCallback(pgvSubTransCallback,NULL);
2143+
2144+
/* Install hooks. */
2145+
prev_ExecutorEnd=ExecutorEnd_hook;
2146+
ExecutorEnd_hook=variable_ExecutorEnd;
20762147
}
20772148

20782149
/*
@@ -2083,4 +2154,5 @@ _PG_fini(void)
20832154
{
20842155
UnregisterXactCallback(pgvTransCallback,NULL);
20852156
UnregisterSubXactCallback(pgvSubTransCallback,NULL);
2157+
ExecutorEnd_hook=prev_ExecutorEnd;
20862158
}

‎pg_variables.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ extern void check_record_key(Variable *variable, Oid typid);
155155
externvoidinsert_record(Variable*variable,HeapTupleHeadertupleHeader);
156156
externboolupdate_record(Variable*variable,HeapTupleHeadertupleHeader);
157157
externbooldelete_record(Variable*variable,Datumvalue,boolis_null);
158+
externvoidremoveObject(TransObject*object,TransObjectTypetype);
158159

159160
#defineGetActualState(object) \
160161
(dlist_head_element(TransState, node, &((TransObject *) object)->states))

‎pg_variables_record.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,29 @@ init_record(RecordVar *record, TupleDesc tupdesc, Variable *variable)
8181
TYPECACHE_HASH_PROC_FINFO |
8282
TYPECACHE_CMP_PROC_FINFO);
8383

84+
/*
85+
* In case something went wrong, you need to roll back the changes before
86+
* completing the transaction, because the variable may be regular
87+
* and not present in list of changed vars.
88+
*/
8489
if (!OidIsValid(typentry->hash_proc_finfo.fn_oid))
90+
{
91+
/* At this point variable is just created, so we simply remove it. */
92+
removeObject(&variable->transObject,TRANS_VARIABLE);
8593
ereport(ERROR,
8694
(errcode(ERRCODE_UNDEFINED_FUNCTION),
8795
errmsg("could not identify a hash function for type %s",
8896
format_type_be(keyid))));
97+
}
8998

9099
if (!OidIsValid(typentry->cmp_proc_finfo.fn_oid))
100+
{
101+
removeObject(&variable->transObject,TRANS_VARIABLE);
91102
ereport(ERROR,
92103
(errcode(ERRCODE_UNDEFINED_FUNCTION),
93104
errmsg("could not identify a matching function for type %s",
94105
format_type_be(keyid))));
106+
}
95107

96108
/* Initialize the record */
97109

‎sql/pg_variables.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ SELECT pgv_insert('vars3', 'r1', row(1, 'str1', 'str2'));
153153
SELECT pgv_insert('vars3','r1', row(1,1));
154154
SELECT pgv_insert('vars3','r1', row('str1','str1'));
155155

156+
SELECT pgv_select('vars3','r1')LIMIT2;
157+
SELECT pgv_select('vars3','r1')LIMIT2 OFFSET2;
158+
156159
SELECT pgv_select('vars3','r1');
157160
SELECT pgv_select('vars3','r1',1);
158161
SELECT pgv_select('vars3','r1',0);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp