@@ -76,7 +76,8 @@ 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 );
80+ static bool isVarChangedInUpperTrans (HashVariableEntry * variable );
8081static void addToChangedVars (HashPackageEntry * package ,HashVariableEntry * variable );
8182
8283#define CHECK_ARGS_FOR_NULL () \
@@ -100,12 +101,11 @@ static HashPackageEntry *LastPackage = NULL;
100101static HashVariableEntry * LastVariable = NULL ;
101102
102103/*
103- *List of variables, changed intop level transaction. Used to limit
104+ *Stack oflists of variables, changed ineach transaction level . Used to limit
104105 * number of proceeded variables on start of transaction.
105106 */
106- static dlist_head * changedVars = NULL ;
107- static MemoryContext changedVarsContext = NULL ;
108107static dlist_head * changedVarsStack = NULL ;
108+ static MemoryContext changedVarsContext = NULL ;
109109#define get_actual_changed_vars_list () \
110110((dlist_head_element(ChangedVarsStackNode, node, changedVarsStack))-> \
111111 changedVarsList)
@@ -621,7 +621,7 @@ variable_insert(PG_FUNCTION_ARGS)
621621errmsg ("variable \"%s\" already created as %sTRANSACTIONAL" ,
622622key ,LastVariable -> is_transactional ?"" :"NOT " )));
623623}
624- if (!isVarChangedInTrans (variable )&& variable -> is_transactional )
624+ if (!isVarChangedInCurrentTrans (variable )&& variable -> is_transactional )
625625{
626626createSavepoint (package ,variable );
627627addToChangedVars (package ,variable );
@@ -707,7 +707,7 @@ variable_update(PG_FUNCTION_ARGS)
707707else
708708variable = LastVariable ;
709709
710- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
710+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
711711{
712712createSavepoint (package ,variable );
713713addToChangedVars (package ,variable );
@@ -785,7 +785,7 @@ variable_delete(PG_FUNCTION_ARGS)
785785else
786786variable = LastVariable ;
787787
788- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
788+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
789789{
790790createSavepoint (package ,variable );
791791addToChangedVars (package ,variable );
@@ -1220,7 +1220,7 @@ remove_packages(PG_FUNCTION_ARGS)
12201220
12211221packagesHash = NULL ;
12221222ModuleContext = NULL ;
1223- changedVars = NULL ;
1223+ changedVarsStack = NULL ;
12241224
12251225PG_RETURN_VOID ();
12261226}
@@ -1663,7 +1663,7 @@ createVariableInternal(HashPackageEntry *package, text *name, Oid typid,
16631663 * For each transaction level there should be own savepoint.
16641664 * New value should be stored in a last state.
16651665 */
1666- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
1666+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
16671667{
16681668createSavepoint (package ,variable );
16691669}
@@ -1769,6 +1769,11 @@ releaseSavepoint(HashVariableEntry *variable)
17691769dlist_delete (nodeToDelete );
17701770pfree (historyEntryToDelete );
17711771}
1772+ /*
1773+ * If variable was changed in subtransaction, so it is considered it
1774+ * was changed in parent transaction.
1775+ */
1776+ (get_actual_value (variable )-> level )-- ;
17721777}
17731778
17741779/*
@@ -1792,22 +1797,32 @@ rollbackSavepoint(HashPackageEntry *package, HashVariableEntry *variable)
17921797 * Check if variable was changed in current transaction level
17931798 */
17941799static bool
1795- isVarChangedInTrans (HashVariableEntry * variable )
1800+ isVarChangedInCurrentTrans (HashVariableEntry * variable )
17961801{
1797- dlist_iter iter ;
1798- dlist_head * changedVars ;
1802+ ValueHistoryEntry * var_state ;
17991803
18001804if (!changedVarsStack )
18011805return false;
18021806
1803- changedVars = get_actual_changed_vars_list ();
1804- dlist_foreach (iter ,changedVars )
1805- {
1806- ChangedVarsNode * cvn ;
1807+ var_state = get_actual_value (variable );
1808+ return (var_state -> level == GetCurrentTransactionNestLevel ());
1809+ }
18071810
1808- cvn = dlist_container (ChangedVarsNode ,node ,iter .cur );
1809- if (cvn -> variable == variable )
1810- return true;
1811+ /*
1812+ * Check if variable was changed in parent transaction level
1813+ */
1814+ static bool
1815+ isVarChangedInUpperTrans (HashVariableEntry * variable )
1816+ {
1817+ ValueHistoryEntry * var_state ,
1818+ * var_prev_state ;
1819+
1820+ var_state = get_actual_value (variable );
1821+
1822+ if (dlist_has_next (& variable -> data ,& var_state -> node ))
1823+ {
1824+ var_prev_state = get_history_entry (var_state -> node .next );
1825+ return (var_prev_state -> level == (GetCurrentTransactionNestLevel ()- 1 ));
18111826}
18121827return false;
18131828}
@@ -1890,12 +1905,12 @@ popChangedVarsStack()
18901905{
18911906if (changedVarsStack )
18921907{
1893- ChangedVarsStackNode * cvse ;
1908+ ChangedVarsStackNode * cvsn ;
18941909
18951910Assert (!dlist_is_empty (changedVarsStack ));
1896- cvse = dlist_container (ChangedVarsStackNode ,node ,
1911+ cvsn = dlist_container (ChangedVarsStackNode ,node ,
18971912dlist_pop_head_node (changedVarsStack ));
1898- MemoryContextDelete (cvse -> ctx );
1913+ MemoryContextDelete (cvsn -> ctx );
18991914if (dlist_is_empty (changedVarsStack ))
19001915{
19011916MemoryContextDelete (changedVarsContext );
@@ -1905,6 +1920,20 @@ popChangedVarsStack()
19051920}
19061921}
19071922
1923+ /*
1924+ * Initialize an instance of ChangedVarsNode datatype
1925+ */
1926+ static inline ChangedVarsNode *
1927+ initChangedVarsNode (MemoryContext ctx ,HashPackageEntry * package ,HashVariableEntry * variable )
1928+ {
1929+ ChangedVarsNode * cvn ;
1930+
1931+ cvn = MemoryContextAllocZero (ctx ,sizeof (ChangedVarsNode ));
1932+ cvn -> package = package ;
1933+ cvn -> variable = variable ;
1934+ return cvn ;
1935+ }
1936+
19081937/*
19091938 * Add a variable to list of changed vars in current transaction level
19101939 */
@@ -1925,20 +1954,19 @@ addToChangedVars(HashPackageEntry *package, HashVariableEntry *variable)
19251954
19261955Assert (changedVarsStack && changedVarsContext );
19271956
1928- if (!isVarChangedInTrans (variable ))
1957+ if (!isVarChangedInCurrentTrans (variable ))
19291958{
19301959ChangedVarsNode * cvn ;
19311960
19321961cvsn = dlist_head_element (ChangedVarsStackNode ,node ,changedVarsStack );
1933- cvn = MemoryContextAllocZero (cvsn -> ctx ,sizeof (ChangedVarsNode ));
1934- cvn -> package = package ;
1935- cvn -> variable = variable ;
1962+ cvn = initChangedVarsNode (cvsn -> ctx ,package ,variable );
19361963dlist_push_head (cvsn -> changedVarsList ,& cvn -> node );
1964+ get_actual_value (cvn -> variable )-> level = GetCurrentTransactionNestLevel ();
19371965}
19381966}
19391967
19401968/*
1941- * If variable waschenged in some subtransaction, it is considered that it was
1969+ * If variable waschanged in some subtransaction, it is considered that it was
19421970 * changed in parent transaction. So it is important to add this variable to
19431971 * list of changes of parent transaction. But if var was already changed in
19441972 * upper level, it has savepoint there, so we need to release it.
@@ -1957,13 +1985,25 @@ levelUpOrRelease()
19571985Assert (!dlist_is_empty (changedVarsStack ));
19581986dlist_foreach (iter ,bottom_list -> changedVarsList )
19591987{
1960- ChangedVarsNode * cvn ;
1988+ ChangedVarsNode * cvn_old ;
19611989
1962- cvn = dlist_container (ChangedVarsNode ,node ,iter .cur );
1963- if (isVarChangedInTrans ( cvn -> variable ))
1964- releaseSavepoint (cvn -> variable );
1990+ cvn_old = dlist_container (ChangedVarsNode ,node ,iter .cur );
1991+ if (isVarChangedInUpperTrans ( cvn_old -> variable ))
1992+ releaseSavepoint (cvn_old -> variable );
19651993else
1966- addToChangedVars (cvn -> package ,cvn -> variable );
1994+ {
1995+ ChangedVarsNode * cvn_new ;
1996+ ChangedVarsStackNode * cvsn ;
1997+
1998+ /*
1999+ * Impossible to push in upper list existing node because
2000+ * it was created in another context
2001+ */
2002+ cvsn = dlist_head_element (ChangedVarsStackNode ,node ,changedVarsStack );
2003+ cvn_new = initChangedVarsNode (cvsn -> ctx ,cvn_old -> package ,cvn_old -> variable );
2004+ dlist_push_head (cvsn -> changedVarsList ,& cvn_new -> node );
2005+ (get_actual_value (cvn_new -> variable )-> level )-- ;
2006+ }
19672007}
19682008MemoryContextDelete (bottom_list -> ctx );
19692009}