@@ -71,8 +71,14 @@ static bool isObjectChangedInCurrentTrans(TransObject *object);
7171static bool isObjectChangedInUpperTrans (TransObject * object );
7272
7373static void addToChangesStack (TransObject * object ,TransObjectType type );
74+ static void addToChangesStackUpperLevel (TransObject * object ,
75+ TransObjectType type );
7476static void pushChangesStack (void );
7577
78+ static int numOfRegVars (Package * package );
79+ /* Debug function */
80+ static int _numOfTransVars (Package * package );
81+
7682/* Constructors */
7783static void makePackHTAB (Package * package ,bool is_trans );
7884static inline ChangedObject * makeChangedObject (TransObject * object ,
@@ -892,10 +898,13 @@ remove_variable(PG_FUNCTION_ARGS)
892898addToChangesStack (transObject ,TRANS_VARIABLE );
893899}
894900GetActualState (variable )-> is_valid = false;
901+ numOfTransVars (package )-- ;
895902}
896903else
897904removeObject (& variable -> transObject ,TRANS_VARIABLE );
898905
906+ Assert (numOfTransVars (package )== _numOfTransVars (package ));
907+
899908resetVariablesCache (false);
900909
901910PG_FREE_IF_COPY (package_name ,0 );
@@ -950,6 +959,7 @@ removePackageInternal(Package *package)
950959addToChangesStack (transObject ,TRANS_PACKAGE );
951960}
952961GetActualState (package )-> is_valid = false;
962+ numOfTransVars (package )= 0 ;
953963}
954964
955965static bool
@@ -1338,7 +1348,8 @@ getPackage(text *name, bool strict)
13381348{
13391349package = (Package * )hash_search (packagesHash ,key ,HASH_FIND ,& found );
13401350
1341- if (found && GetActualState (package )-> is_valid )
1351+ if (found && GetActualState (package )-> is_valid &&
1352+ numOfTransVars (package )+ numOfRegVars (package ))
13421353return package ;
13431354}
13441355/* Package not found or it's current state is "invalid" */
@@ -1410,17 +1421,15 @@ createPackage(text *name, bool is_trans)
14101421packState = MemoryContextAllocZero (ModuleContext ,sizeof (PackState ));
14111422dlist_push_head (GetStateStorage (package ),& (packState -> state .node ));
14121423packState -> state .is_valid = true;
1424+ packState -> trans_var_num = 0 ;
1425+ /* Add to changes list */
1426+ if (!isObjectChangedInCurrentTrans (& package -> transObject ))
1427+ addToChangesStack (& package -> transObject ,TRANS_PACKAGE );
14131428}
14141429
14151430/* Create corresponding HTAB if not exists */
14161431if (!pack_htab (package ,is_trans ))
14171432makePackHTAB (package ,is_trans );
1418- /* Add to changes list */
1419- if (!isObjectChangedInCurrentTrans (& package -> transObject ))
1420- {
1421- createSavepoint (& package -> transObject ,TRANS_PACKAGE );
1422- addToChangesStack (& package -> transObject ,TRANS_PACKAGE );
1423- }
14241433
14251434return package ;
14261435}
@@ -1586,7 +1595,13 @@ createVariableInternal(Package *package, text *name, Oid typid, bool is_record,
15861595}
15871596}
15881597
1598+ if (is_transactional &&
1599+ (!found || !GetActualState (variable )-> is_valid ))
1600+ numOfTransVars (package )++ ;
15891601GetActualState (variable )-> is_valid = true;
1602+
1603+ Assert (numOfTransVars (package )== _numOfTransVars (package ));
1604+
15901605/* If it is necessary, put variable to changedVars */
15911606if (is_transactional )
15921607addToChangesStack (transObject ,TRANS_VARIABLE );
@@ -1715,8 +1730,11 @@ createSavepoint(TransObject *object, TransObjectType type)
17151730
17161731prevState = GetActualState (object );
17171732if (type == TRANS_PACKAGE )
1733+ {
17181734newState = (TransState * )MemoryContextAllocZero (ModuleContext ,
17191735sizeof (PackState ));
1736+ ((PackState * )newState )-> trans_var_num = ((PackState * )prevState )-> trans_var_num ;
1737+ }
17201738else
17211739{
17221740Variable * var = (Variable * )object ;
@@ -1729,6 +1747,15 @@ createSavepoint(TransObject *object, TransObjectType type)
17291747newState -> is_valid = prevState -> is_valid ;
17301748}
17311749
1750+ static int
1751+ numOfRegVars (Package * package )
1752+ {
1753+ if (package -> varHashRegular )
1754+ return hash_get_num_entries (package -> varHashRegular );
1755+ else
1756+ return 0 ;
1757+ }
1758+
17321759/*
17331760 * Rollback object to its previous state
17341761 */
@@ -1738,32 +1765,27 @@ rollbackSavepoint(TransObject *object, TransObjectType type)
17381765TransState * state ;
17391766
17401767state = GetActualState (object );
1741- if (type == TRANS_PACKAGE )
1768+ removeState (object ,type ,state );
1769+
1770+ if (dlist_is_empty (& object -> states ))
17421771{
1743- if (! state -> is_valid && ! isPackageEmpty ((Package * )object ))
1772+ if (type == TRANS_PACKAGE && numOfRegVars ((Package * )object ))
17441773{
1745- if (dlist_has_next (& object -> states ,& state -> node ))
1774+ PackState * packState ;
1775+
1776+ packState = MemoryContextAllocZero (ModuleContext ,sizeof (PackState ));
1777+ dlist_push_head (& object -> states ,& (packState -> state .node ));
1778+ packState -> state .is_valid = true;
1779+ packState -> state .level = GetCurrentTransactionNestLevel ()- 1 ;
1780+ packState -> trans_var_num = 0 ;
1781+
1782+ if (!dlist_is_empty (changesStack ))
17461783{
1747- dlist_pop_head_node (& object -> states );
1748- pfree (state );
1784+ addToChangesStackUpperLevel (object ,type );
17491785}
1750- else
1751- state -> is_valid = true;
1752- /* Restore regular vars HTAB */
1753- makePackHTAB ((Package * )object , false);
17541786}
17551787else
1756- /* Pass current state to parent level */
1757- releaseSavepoint (object ,TRANS_PACKAGE );
1758- }
1759- else
1760- {
1761- /* Remove current state */
1762- removeState (object ,TRANS_VARIABLE ,state );
1763-
1764- /* Remove variable if it was created in rolled back transaction */
1765- if (dlist_is_empty (& object -> states ))
1766- removeObject (object ,TRANS_VARIABLE );
1788+ removeObject (object ,type );
17671789}
17681790}
17691791
@@ -1802,21 +1824,31 @@ releaseSavepoint(TransObject *object, TransObjectType type)
18021824/* If the object does not yet have a record in previous level changesStack,
18031825 * create it. */
18041826else if (!dlist_is_empty (changesStack ))
1805- {
1806- ChangedObject * co_new ;
1807- ChangesStackNode * csn ;
1808- /*
1809- * Impossible to push in upper list existing node
1810- * because it was created in another context
1811- */
1812- csn = dlist_head_element (ChangesStackNode ,node ,changesStack );
1813- co_new = makeChangedObject (object ,csn -> ctx );
1814- dlist_push_head (type == TRANS_PACKAGE ?csn -> changedPacksList :
1815- csn -> changedVarsList ,
1816- & co_new -> node );
1817- }
1827+ addToChangesStackUpperLevel (object ,type );
1828+
18181829/* Change subxact level due to release */
18191830GetActualState (object )-> level -- ;
1831+ if (type == TRANS_PACKAGE )
1832+ {
1833+ Package * package = (Package * )object ;
1834+ Assert (numOfTransVars (package )== _numOfTransVars (package ));
1835+ }
1836+ }
1837+
1838+ static void
1839+ addToChangesStackUpperLevel (TransObject * object ,TransObjectType type )
1840+ {
1841+ ChangedObject * co_new ;
1842+ ChangesStackNode * csn ;
1843+ /*
1844+ * Impossible to push in upper list existing node
1845+ * because it was created in another context
1846+ */
1847+ csn = dlist_head_element (ChangesStackNode ,node ,changesStack );
1848+ co_new = makeChangedObject (object ,csn -> ctx );
1849+ dlist_push_head (type == TRANS_PACKAGE ?csn -> changedPacksList :
1850+ csn -> changedVarsList ,
1851+ & co_new -> node );
18201852}
18211853
18221854/*
@@ -2136,3 +2168,25 @@ _PG_fini(void)
21362168UnregisterSubXactCallback (pgvSubTransCallback ,NULL );
21372169ExecutorEnd_hook = prev_ExecutorEnd ;
21382170}
2171+
2172+ /* Get exact count of valid variables in package. For debug only. */
2173+ static int
2174+ _numOfTransVars (Package * package )
2175+ {
2176+ HASH_SEQ_STATUS vstat ;
2177+ Variable * variable ;
2178+ unsigned long res = 0 ;
2179+
2180+ if (package -> varHashTransact )
2181+ {
2182+ hash_seq_init (& vstat ,package -> varHashTransact );
2183+ while ((variable = (Variable * )hash_seq_search (& vstat ))!= NULL )
2184+ {
2185+ if (GetActualState (variable )-> is_valid &&
2186+ GetActualState (package )-> is_valid )
2187+ res ++ ;
2188+ }
2189+ }
2190+
2191+ return res ;
2192+ }