@@ -76,7 +76,7 @@ static HashVariableEntry *createVariableInternal(HashPackageEntry *package,
7676 text * name , Oid typid ,
7777 bool 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 in top level transaction. Used to limit
103+ * Stack of lists of variables, changed in each 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)
621620 errmsg ("variable \"%s\" already created as %sTRANSACTIONAL" ,
622621 key , LastVariable -> is_transactional ? "" : "NOT " )));
623622 }
624- if (!isVarChangedInTrans (variable ) && variable -> is_transactional )
623+ if (!isVarChangedInCurrentTrans (variable ) && variable -> is_transactional )
625624 {
626625 createSavepoint (package , variable );
627626 addToChangedVars (package , variable );
@@ -707,7 +706,7 @@ variable_update(PG_FUNCTION_ARGS)
707706 else
708707 variable = LastVariable ;
709708
710- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
709+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
711710 {
712711 createSavepoint (package , variable );
713712 addToChangedVars (package , variable );
@@ -785,7 +784,7 @@ variable_delete(PG_FUNCTION_ARGS)
785784 else
786785 variable = LastVariable ;
787786
788- if (variable -> is_transactional && !isVarChangedInTrans (variable ))
787+ if (variable -> is_transactional && !isVarChangedInCurrentTrans (variable ))
789788 {
790789 createSavepoint (package , variable );
791790 addToChangedVars (package , variable );
@@ -1220,7 +1219,7 @@ remove_packages(PG_FUNCTION_ARGS)
12201219
12211220 packagesHash = NULL ;
12221221 ModuleContext = NULL ;
1223- changedVars = NULL ;
1222+ changedVarsStack = NULL ;
12241223
12251224 PG_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 {
16681667 createSavepoint (package , variable );
16691668 }
@@ -1769,6 +1768,7 @@ releaseSavepoint(HashVariableEntry *variable)
17691768 dlist_delete (nodeToDelete );
17701769 pfree (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
18001799 if (!changedVarsStack )
18011800 return 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
19261937 Assert (changedVarsStack && changedVarsContext );
19271938
1928- if (!isVarChangedInTrans (variable ))
1939+ if (!isVarChangedInCurrentTrans (variable ))
19291940 {
19301941 ChangedVarsNode * cvn ;
19311942
@@ -1934,6 +1945,7 @@ addToChangedVars(HashPackageEntry *package, HashVariableEntry *variable)
19341945 cvn -> package = package ;
19351946 cvn -> variable = variable ;
19361947 dlist_push_head (cvsn -> changedVarsList , & cvn -> node );
1948+ get_actual_value (cvn -> variable )-> level = GetCurrentTransactionNestLevel ();
19371949 }
19381950}
19391951
@@ -1957,13 +1969,27 @@ levelUpOrRelease()
19571969 Assert (!dlist_is_empty (changedVarsStack ));
19581970 dlist_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 );
19651977 else
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 }
19681994 MemoryContextDelete (bottom_list -> ctx );
19691995 }
0 commit comments