@@ -57,6 +57,7 @@ static Variable *createVariableInternal(Package *package,
5757text * name ,Oid typid ,
5858bool is_transactional );
5959static void removePackageInternal (Package * package );
60+ static void resetVariablesCache (bool with_package );
6061
6162/* Functions to work with transactional objects */
6263static void createSavepoint (TransObject * object ,TransObjectType type );
@@ -99,6 +100,8 @@ static MemoryContext ModuleContext = NULL;
99100static Package * LastPackage = NULL ;
100101/* Recent variable */
101102static Variable * LastVariable = NULL ;
103+ /* Recent row type id */
104+ static Oid LastTypeId = InvalidOid ;
102105
103106
104107/* This stack contains lists of changed variables and packages per each subxact level */
@@ -291,7 +294,7 @@ variable_insert(PG_FUNCTION_ARGS)
291294
292295Oid tupType ;
293296int32 tupTypmod ;
294- TupleDesc tupdesc ;
297+ TupleDesc tupdesc = NULL ;
295298RecordVar * record ;
296299
297300/* Checks */
@@ -360,23 +363,34 @@ variable_insert(PG_FUNCTION_ARGS)
360363/* Insert a record */
361364tupType = HeapTupleHeaderGetTypeId (rec );
362365tupTypmod = HeapTupleHeaderGetTypMod (rec );
363- tupdesc = lookup_rowtype_tupdesc (tupType ,tupTypmod );
364366
365367record = & (GetActualValue (variable ).record );
366368if (!record -> tupdesc )
367369{
368370/*
369371 * This is the first record for the var_name. Initialize record.
370372 */
373+ tupdesc = lookup_rowtype_tupdesc (tupType ,tupTypmod );
371374init_record (record ,tupdesc ,variable );
372375}
373- else
376+ else if (LastTypeId == RECORDOID || !OidIsValid (LastTypeId )||
377+ LastTypeId != tupType )
378+ {
379+ /*
380+ * We need to check attributes of the new row if this is a transient
381+ * record type or if last record has different id.
382+ */
383+ tupdesc = lookup_rowtype_tupdesc (tupType ,tupTypmod );
374384check_attributes (variable ,tupdesc );
385+ }
386+
387+ LastTypeId = tupType ;
375388
376389insert_record (variable ,rec );
377390
378391/* Release resources */
379- ReleaseTupleDesc (tupdesc );
392+ if (tupdesc )
393+ ReleaseTupleDesc (tupdesc );
380394
381395PG_FREE_IF_COPY (package_name ,0 );
382396PG_FREE_IF_COPY (var_name ,1 );
@@ -396,7 +410,6 @@ variable_update(PG_FUNCTION_ARGS)
396410bool res ;
397411Oid tupType ;
398412int32 tupTypmod ;
399- TupleDesc tupdesc ;
400413
401414/* Checks */
402415CHECK_ARGS_FOR_NULL ();
@@ -447,14 +460,22 @@ variable_update(PG_FUNCTION_ARGS)
447460/* Update a record */
448461tupType = HeapTupleHeaderGetTypeId (rec );
449462tupTypmod = HeapTupleHeaderGetTypMod (rec );
450- tupdesc = lookup_rowtype_tupdesc (tupType ,tupTypmod );
451463
452- check_attributes (variable ,tupdesc );
464+ if (LastTypeId == RECORDOID || !OidIsValid (LastTypeId )||
465+ LastTypeId != tupType )
466+ {
467+ TupleDesc tupdesc = NULL ;
468+
469+ tupdesc = lookup_rowtype_tupdesc (tupType ,tupTypmod );
470+ check_attributes (variable ,tupdesc );
471+ ReleaseTupleDesc (tupdesc );
472+ }
473+
474+ LastTypeId = tupType ;
475+
453476res = update_record (variable ,rec );
454477
455478/* Release resources */
456- ReleaseTupleDesc (tupdesc );
457-
458479PG_FREE_IF_COPY (package_name ,0 );
459480PG_FREE_IF_COPY (var_name ,1 );
460481
@@ -867,8 +888,7 @@ remove_variable(PG_FUNCTION_ARGS)
867888GetActualState (variable )-> is_valid = false;
868889}
869890
870- /* Remove variable from cache */
871- LastVariable = NULL ;
891+ resetVariablesCache (false);
872892
873893PG_FREE_IF_COPY (package_name ,0 );
874894PG_FREE_IF_COPY (var_name ,1 );
@@ -904,9 +924,7 @@ remove_package(PG_FUNCTION_ARGS)
904924errmsg ("unrecognized package \"%s\"" ,key )));
905925}
906926
907- /* Remove package and variable from cache */
908- LastPackage = NULL ;
909- LastVariable = NULL ;
927+ resetVariablesCache (true);
910928
911929PG_FREE_IF_COPY (package_name ,0 );
912930PG_RETURN_VOID ();
@@ -934,6 +952,20 @@ removePackageInternal(Package *package)
934952GetActualState (package )-> is_valid = false;
935953}
936954
955+ /*
956+ * Reset cache variables to their default values. It is necessary to do in case
957+ * of some changes: removing, rollbacking, etc.
958+ */
959+ static void
960+ resetVariablesCache (bool with_package )
961+ {
962+ /* Remove package and variable from cache */
963+ if (with_package )
964+ LastPackage = NULL ;
965+ LastVariable = NULL ;
966+ LastTypeId = InvalidOid ;
967+ }
968+
937969/*
938970 * Remove all packages and variables.
939971 * Memory context will be released after committing.
@@ -955,9 +987,7 @@ remove_packages(PG_FUNCTION_ARGS)
955987removePackageInternal (package );
956988}
957989
958- /* Remove package and variable from cache */
959- LastPackage = NULL ;
960- LastVariable = NULL ;
990+ resetVariablesCache (true);
961991
962992PG_RETURN_VOID ();
963993}
@@ -1632,8 +1662,7 @@ removeObject(TransObject *object, TransObjectType type)
16321662/* Remove object from hash table */
16331663hash_search (hash ,object -> name ,HASH_REMOVE ,& found );
16341664
1635- LastPackage = NULL ;
1636- LastVariable = NULL ;
1665+ resetVariablesCache (true);
16371666}
16381667
16391668/*
@@ -2004,8 +2033,7 @@ processChanges(Action action)
20042033MemoryContextDelete (ModuleContext );
20052034packagesHash = NULL ;
20062035ModuleContext = NULL ;
2007- LastPackage = NULL ;
2008- LastVariable = NULL ;
2036+ resetVariablesCache (true);
20092037changesStack = NULL ;
20102038changesStackContext = NULL ;
20112039}