EDG_WLL_QUERY_OP_GREATER,       /**< attribute is less than the operand value \see _edg_wll_QueryRec */
        EDG_WLL_QUERY_OP_WITHIN,        /**< attribute is in given interval \see _edg_wll_QueryRec */
        EDG_WLL_QUERY_OP_UNEQUAL,       /**< attribute is not equal to the operand value \see _edg_wll_QueryRec */
+       EDG_WLL_QUERY_OP_CHANGED,       /**< attribute has changed from last check; supported only in notification matching 
+                                               \see _edg_wll_QueryRec */
 } edg_wll_QueryOp;
 
 
 
 
 
 extern int unset_proxy_flag(edg_wll_Context, edg_wlc_JobId);
-extern int edg_wll_NotifMatch(edg_wll_Context, const edg_wll_JobStat *);
+extern int edg_wll_NotifMatch(edg_wll_Context, const edg_wll_JobStat *, const edg_wll_JobStat *);
 extern int enable_lcas;
 
 
-static int db_store_finalize(edg_wll_Context ctx, char *event, edg_wll_Event *ev, edg_wll_JobStat *newstat, int reg_to_JP);
+static int db_store_finalize(edg_wll_Context ctx, char *event, edg_wll_Event *ev, edg_wll_JobStat *oldstat, edg_wll_JobStat *newstat, int reg_to_JP);
 
 
 int
   edg_wll_Event        *ev = NULL;
   int                  seq, reg_to_JP = 0, local_job;
   edg_wll_JobStat      newstat;
+  edg_wll_JobStat      oldstat;
 
 
   edg_wll_ResetError(ctx);
   memset(&newstat,0,sizeof newstat);
+  memset(&oldstat,0,sizeof oldstat);
 
   if(edg_wll_ParseEvent(ctx, event, &ev)) goto err;
 
                        edg_wll_FreeStatus(&newstat);
                        newstat.state = EDG_WLL_JOB_UNDEF;
                }
-               if (edg_wll_StepIntState(ctx,ev->any.jobId, ev, seq, &newstat)) goto rollback;
+               if (edg_wll_StepIntState(ctx,ev->any.jobId, ev, seq, &oldstat, &newstat)) goto rollback;
                
                if (newstat.remove_from_proxy) 
                        if (edg_wll_PurgeServerProxy(ctx, ev->any.jobId)) goto rollback;
   if (edg_wll_Error(ctx, NULL, NULL)) goto err;
 
 
-  db_store_finalize(ctx, event, ev, &newstat, reg_to_JP);
+  db_store_finalize(ctx, event, ev, &oldstat, &newstat, reg_to_JP);
 
 
 err:
   if(ev) { edg_wll_FreeEvent(ev); free(ev); }
   if ( newstat.state ) edg_wll_FreeStatus(&newstat);
+  if ( oldstat.state ) edg_wll_FreeStatus(&oldstat);
 
   return edg_wll_Error(ctx,NULL,NULL);
 }
   int  seq;
   int   err;
   edg_wll_JobStat      newstat;
+  edg_wll_JobStat      oldstat;
 
 
   edg_wll_ResetError(ctx);
   memset(&newstat,0,sizeof newstat);
+  memset(&oldstat,0,sizeof oldstat);
 
   /* Transaction opened from db_store */
 
   }
 #endif
 
-  err = edg_wll_StepIntStateParent(ctx,ev->any.jobId, ev, seq, is, ctx->isProxy? NULL: &newstat);
+  err = edg_wll_StepIntStateParent(ctx,ev->any.jobId, ev, seq, is, &oldstat, ctx->isProxy? NULL: &newstat);
 
   if (err) goto err;
 
     assert(event);
   }
 
-  db_store_finalize(ctx, event, ev, &newstat, 0);
+  db_store_finalize(ctx, event, ev, &oldstat, &newstat, 0);
 
 err:
 
   free(event);
   if ( newstat.state ) edg_wll_FreeStatus(&newstat);
+  if ( oldstat.state ) edg_wll_FreeStatus(&oldstat);
   
   return edg_wll_Error(ctx,NULL,NULL);
 }
 }
 
 
-static int db_store_finalize(edg_wll_Context ctx, char *event, edg_wll_Event *ev, edg_wll_JobStat *newstat, int reg_to_JP) 
+static int db_store_finalize(edg_wll_Context ctx, char *event, edg_wll_Event *ev, edg_wll_JobStat *oldstat, edg_wll_JobStat *newstat, int reg_to_JP) 
 {
        int     local_job = is_job_local(ctx, ev->any.jobId);
 
                        if ((ev->any.priority & EDG_WLL_LOGFLAG_DIRECT) || local_job) 
                                /* event will not arrive to server, only flag was set           */
                                /* check whether some pending notifications are not triggered   */
-                               edg_wll_NotifMatch(ctx, newstat);
+                               edg_wll_NotifMatch(ctx, oldstat, newstat);
                        }
                else {
-                               edg_wll_NotifMatch(ctx, newstat);
+                               edg_wll_NotifMatch(ctx, oldstat, newstat);
                }
        }
 
 
                                        edg_wll_Event *e,
                                        int seq,
                                        intJobStat *ijsp,
+                                       edg_wll_JobStat *oldstat,
                                        edg_wll_JobStat *stat_out)
 {
        int             res;
        int             be_strict = 0;
        char            *errstring = NULL;
-       edg_wll_JobStat oldstat;
        char            *oldstat_rgmaline = NULL;
 
 
-       memset(&oldstat,0,sizeof oldstat);
-
-       edg_wll_CpyStatus(&ijsp->pub,&oldstat);
+       edg_wll_CpyStatus(&ijsp->pub,oldstat);
 
        if (ctx->rgma_export) oldstat_rgmaline = write2rgma_statline(ijsp);
 
        res = processEvent(ijsp, e, seq, be_strict, &errstring);
        if (res == RET_FATAL || res == RET_INTERNAL) { /* !strict */
-               edg_wll_FreeStatus(&oldstat);
+               edg_wll_FreeStatus(oldstat);
+               memset(oldstat,0,sizeof *oldstat);
                return edg_wll_SetError(ctx, EINVAL, errstring);
        }
        // XXX: store it in update_parent status ?? 
        edg_wll_StoreIntState(ctx, ijsp, seq);
 
-       edg_wll_UpdateStatistics(ctx,&oldstat,e,&ijsp->pub);
+       edg_wll_UpdateStatistics(ctx,oldstat,e,&ijsp->pub);
 
        if (ctx->rgma_export) write2rgma_chgstatus(ijsp, oldstat_rgmaline);
 
        if (stat_out) {
                edg_wll_CpyStatus(&ijsp->pub, stat_out);
        }
-       edg_wll_FreeStatus(&oldstat);
 
        return edg_wll_Error(ctx, NULL, NULL);
 }
                                        glite_jobid_const_t job,
                                        edg_wll_Event *e,
                                        int seq,
+                                       edg_wll_JobStat *oldstat,
                                        edg_wll_JobStat *stat_out)
 {
        intJobStat      *ijsp;
        int             be_strict = 0;
        char            *errstring = NULL;
        intJobStat      jobstat;
-       edg_wll_JobStat oldstat;
        char            *oldstat_rgmaline = NULL;
 
 
-       memset(&oldstat,0,sizeof oldstat);
-
        if (!edg_wll_LoadIntState(ctx, job, DONT_LOCK, seq - 1, &ijsp)) {
-               edg_wll_CpyStatus(&ijsp->pub,&oldstat);
+               edg_wll_CpyStatus(&ijsp->pub,oldstat);
 
                if (ctx->rgma_export) oldstat_rgmaline = write2rgma_statline(ijsp);
 
                res = processEvent(ijsp, e, seq, be_strict, &errstring);
                if (res == RET_FATAL || res == RET_INTERNAL) { /* !strict */
-                       edg_wll_FreeStatus(&oldstat);
+                       edg_wll_FreeStatus(oldstat);
+                       memset(oldstat,0,sizeof *oldstat);
                        return edg_wll_SetError(ctx, EINVAL, errstring);
                }
                edg_wll_StoreIntState(ctx, ijsp, seq);
 
-               edg_wll_UpdateStatistics(ctx,&oldstat,e,&ijsp->pub);
+               edg_wll_UpdateStatistics(ctx,oldstat,e,&ijsp->pub);
 
                /* check whether subjob state change does not change parent state */
-               if ((ijsp->pub.parent_job) && (oldstat.state != ijsp->pub.state)) { 
-                       if (update_parent_status(ctx, &oldstat, ijsp, e))
+               if ((ijsp->pub.parent_job) && (oldstat->state != ijsp->pub.state)) { 
+                       if (update_parent_status(ctx, oldstat, ijsp, e)) {
+                               edg_wll_FreeStatus(oldstat);
+                               memset(oldstat,0,sizeof *oldstat);
                                return edg_wll_SetError(ctx, EINVAL, "update_parent_status()");
+                       }
                }
 
                if (ctx->rgma_export) write2rgma_chgstatus(ijsp, oldstat_rgmaline);
                }
                else destroy_intJobStat(ijsp);
                free(ijsp);
-               edg_wll_FreeStatus(&oldstat);
        }
        else if (!edg_wll_intJobStatus(ctx, job, flags,&jobstat, js_enable_store, 1)) 
        {
 
 
 
 /* update stored job state according to new event */
-edg_wll_ErrorCode edg_wll_StepIntState(edg_wll_Context ctx, glite_jobid_const_t job, edg_wll_Event *e, int seq, edg_wll_JobStat *stat_out);
+edg_wll_ErrorCode edg_wll_StepIntState(edg_wll_Context ctx, glite_jobid_const_t job, edg_wll_Event *e, int seq, edg_wll_JobStat *old_stat, edg_wll_JobStat *stat_out);
 
-edg_wll_ErrorCode edg_wll_StepIntStateParent(edg_wll_Context,glite_jobid_const_t,edg_wll_Event *,int,intJobStat *,edg_wll_JobStat *);
+edg_wll_ErrorCode edg_wll_StepIntStateParent(edg_wll_Context,glite_jobid_const_t,edg_wll_Event *,int,intJobStat *, edg_wll_JobStat *old_stat, edg_wll_JobStat *);
 
 /* create embriotic job state for DAGs' subjob */
 
 
                                case EDG_WLL_QUERY_OP_WITHIN: GS ("within");
                                        break;
                                case EDG_WLL_QUERY_OP_UNEQUAL: GS ("!=");
+                                       break;
+                               case EDG_WLL_QUERY_OP_CHANGED: GS ("changed");
+                                       break;
                        }
                        char *buf;
                        switch (l2->attr){
 
 
 int edg_wll_NotifExpired(edg_wll_Context,const char *);
 
-int edg_wll_NotifMatch(edg_wll_Context ctx, const edg_wll_JobStat *stat)
+int edg_wll_NotifMatch(edg_wll_Context ctx, const edg_wll_JobStat *oldstat, const edg_wll_JobStat *stat)
 {
        edg_wll_NotifId         nid = NULL;
        char    *jobq,*ju = NULL,*jobc[6];
 
 #define LESS           lbt__queryOp__LESS
 #define GREATER                lbt__queryOp__GREATER
 #define WITHIN         lbt__queryOp__WITHIN
+#define CHANGED                lbt__queryOp__CHANGED
 
 #define SUBMITTED      lbt__statName__SUBMITTED
 #define WAITING                lbt__statName__WAITING
 
        case LESS: *out = EDG_WLL_QUERY_OP_LESS; break;
        case GREATER: *out = EDG_WLL_QUERY_OP_GREATER; break;
        case WITHIN: *out = EDG_WLL_QUERY_OP_WITHIN; break;
+       case CHANGED: *out = EDG_WLL_QUERY_OP_CHANGED; break;
        }
 }
 
        case EDG_WLL_QUERY_OP_LESS: *out = LESS; break;
        case EDG_WLL_QUERY_OP_GREATER: *out = GREATER; break;
        case EDG_WLL_QUERY_OP_WITHIN: *out = WITHIN; break;
+       case EDG_WLL_QUERY_OP_CHANGED: *out = CHANGED; break;
        default: assert(0);
        }
 }
 
                        <val name="GREATER"> Attribute is greater than the specified value or equal </val>
                        <val name="WITHIN"> Attribute is withing a range (queryRecord.value2 must be specified) </val>
                        <val name="UNEQUAL"> Attribute is not equal to the specified value.</val>
+                       <val name="CHANGED"> Attribute has changed its value from last check (notification conditions only).</val>
                </enum>
                
                <choice name="queryRecValue">