@@ -76,7 +76,7 @@ static HashVariableEntry *createVariableInternal(HashPackageEntry *package,
7676text * name ,Oid typid ,
7777bool is_transactional );
7878static void createSavepoint (HashPackageEntry * package ,HashVariableEntry * variable );
79- static bool isVarChangedInTrans (HashVariableEntry * variable );
79+ static bool isVarChangedInCurrentTrans (HashVariableEntry * variable );
8080static void addToChangedVars (HashPackageEntry * package ,HashVariableEntry * variable );
8181
8282#define CHECK_ARGS_FOR_NULL () \
@@ -100,12 +100,11 @@ static HashPackageEntry *LastPackage = NULL;
100100static HashVariableEntry * LastVariable = NULL ;
101101
102102/*
103- *List of variables, changed intop level transaction. Used to limit
103+ *Stack oflists of variables, changed ineach transaction level . Used to limit
104104 * number of proceeded variables on start of transaction.
105105 */
106- static dlist_head * changedVars = NULL ;
107- static MemoryContext changedVarsContext = NULL ;
108106static dlist_head * changedVarsStack = NULL ;
107+ static MemoryContext changedVarsContext = NULL ;
109108#define get_actual_changed_vars_list () \
110109((dlist_head_element(ChangedVarsStackNode, node, changedVarsStack))-> \
111110 changedVarsList)
@@ -621,7 +620,7 @@ variable_insert(PG_FUNCTION_ARGS)
621620errmsg ("variable \"%s\" already created as %sTRANSACTIONAL" ,
622621key ,LastVariable -> is_transactional ?"" :"NOT " )));
623622}
624- if (!isVarChangedInTrans (variable )&& variable -> is_transactional )
623+ if (!isVarChangedInCurrentTrans (variable )&& variable -> is_transactional )
625624{
626625createSavepoint (package ,variable );
627626addToChangedVars (package ,variable );
@@ -707,7 +706,7 @@ variable_update(PG_FUNCTION_ARGS)
707706else
708707variable = LastVariable ;
709708
710- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
709+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
711710{
712711createSavepoint (package ,variable );
713712addToChangedVars (package ,variable );
@@ -785,7 +784,7 @@ variable_delete(PG_FUNCTION_ARGS)
785784else
786785variable = LastVariable ;
787786
788- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
787+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
789788{
790789createSavepoint (package ,variable );
791790addToChangedVars (package ,variable );
@@ -1220,7 +1219,7 @@ remove_packages(PG_FUNCTION_ARGS)
12201219
12211220packagesHash = NULL ;
12221221ModuleContext = NULL ;
1223- changedVars = NULL ;
1222+ changedVarsStack = NULL ;
12241223
12251224PG_RETURN_VOID ();
12261225}
@@ -1663,7 +1662,7 @@ createVariableInternal(HashPackageEntry *package, text *name, Oid typid,
16631662 * For each transaction level there should be own savepoint.
16641663 * New value should be stored in a last state.
16651664 */
1666- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
1665+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
16671666{
16681667createSavepoint (package ,variable );
16691668}
@@ -1769,6 +1768,7 @@ releaseSavepoint(HashVariableEntry *variable)
17691768dlist_delete (nodeToDelete );
17701769pfree (historyEntryToDelete );
17711770}
1771+ (get_actual_value (variable )-> level )-- ;
17721772}
17731773
17741774/*
@@ -1792,24 +1792,35 @@ rollbackSavepoint(HashPackageEntry *package, HashVariableEntry *variable)
17921792 * Check if variable was changed in current transaction level
17931793 */
17941794static bool
1795- isVarChangedInTrans (HashVariableEntry * variable )
1795+ isVarChangedInCurrentTrans (HashVariableEntry * variable )
17961796{
1797- dlist_iter iter ;
1798- dlist_head * changedVars ;
1797+ ValueHistoryEntry * var_state ;
17991798
18001799if (!changedVarsStack )
18011800return false;
18021801
1803- changedVars = get_actual_changed_vars_list ();
1804- dlist_foreach (iter ,changedVars )
1805- {
1806- ChangedVarsNode * cvn ;
1802+ var_state = get_actual_value (variable );
1803+ return (var_state -> level == GetCurrentTransactionNestLevel ());
1804+ }
18071805
1808- cvn = dlist_container (ChangedVarsNode ,node ,iter .cur );
1809- if (cvn -> variable == variable )
1810- return true;
1806+ /*
1807+ * Check if variable was changed in parent transaction level
1808+ */
1809+ static bool
1810+ isVarChangedInUpperTrans (HashVariableEntry * variable )
1811+ {
1812+ ValueHistoryEntry * var_state ,
1813+ * var_prev_state ;
1814+
1815+ var_state = get_actual_value (variable );
1816+
1817+ if (dlist_has_next (& variable -> data ,& var_state -> node ))
1818+ {
1819+ var_prev_state = get_history_entry (var_state -> node .next );
1820+ return (var_prev_state -> level == (GetCurrentTransactionNestLevel ()- 1 ));
18111821}
1812- return false;
1822+ else
1823+ return false;
18131824}
18141825
18151826/*
@@ -1925,7 +1936,7 @@ addToChangedVars(HashPackageEntry *package, HashVariableEntry *variable)
19251936
19261937Assert (changedVarsStack && changedVarsContext );
19271938
1928- if (!isVarChangedInTrans (variable ))
1939+ if (!isVarChangedInCurrentTrans (variable ))
19291940{
19301941ChangedVarsNode * cvn ;
19311942
@@ -1934,6 +1945,7 @@ addToChangedVars(HashPackageEntry *package, HashVariableEntry *variable)
19341945cvn -> package = package ;
19351946cvn -> variable = variable ;
19361947dlist_push_head (cvsn -> changedVarsList ,& cvn -> node );
1948+ get_actual_value (cvn -> variable )-> level = GetCurrentTransactionNestLevel ();
19371949}
19381950}
19391951
@@ -1957,13 +1969,27 @@ levelUpOrRelease()
19571969Assert (!dlist_is_empty (changedVarsStack ));
19581970dlist_foreach (iter ,bottom_list -> changedVarsList )
19591971{
1960- ChangedVarsNode * cvn ;
1972+ ChangedVarsNode * cvn_old ;
19611973
1962- cvn = dlist_container (ChangedVarsNode ,node ,iter .cur );
1963- if (isVarChangedInTrans ( cvn -> variable ))
1964- releaseSavepoint (cvn -> variable );
1974+ cvn_old = dlist_container (ChangedVarsNode ,node ,iter .cur );
1975+ if (isVarChangedInUpperTrans ( cvn_old -> variable ))
1976+ releaseSavepoint (cvn_old -> variable );
19651977else
1966- addToChangedVars (cvn -> package ,cvn -> variable );
1978+ {
1979+ ChangedVarsNode * cvn_new ;
1980+ ChangedVarsStackNode * cvsn ;
1981+
1982+ /*
1983+ * Impossible to push in upper list existing node because
1984+ * it was created in another context
1985+ */
1986+ cvsn = dlist_head_element (ChangedVarsStackNode ,node ,changedVarsStack );
1987+ cvn_new = MemoryContextAllocZero (cvsn -> ctx ,sizeof (ChangedVarsNode ));
1988+ cvn_new -> package = cvn_old -> package ;
1989+ cvn_new -> variable = cvn_old -> variable ;
1990+ dlist_push_head (cvsn -> changedVarsList ,& cvn_new -> node );
1991+ (get_actual_value (cvn_new -> variable )-> level )-- ;
1992+ }
19671993}
19681994MemoryContextDelete (bottom_list -> ctx );
19691995}