1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 
26 #define DBTUP_C
27 #define DBTUP_TRIGGER_CPP
28 #include "Dbtup.hpp"
29 #include <RefConvert.hpp>
30 #include <ndb_limits.h>
31 #include <pc.hpp>
32 #include <AttributeDescriptor.hpp>
33 #include "AttributeOffset.hpp"
34 #include <AttributeHeader.hpp>
35 #include <signaldata/FireTrigOrd.hpp>
36 #include <signaldata/CreateTrig.hpp>
37 #include <signaldata/CreateTrigImpl.hpp>
38 #include <signaldata/DropTrig.hpp>
39 #include <signaldata/DropTrigImpl.hpp>
40 #include <signaldata/TuxMaint.hpp>
41 #include <signaldata/AlterIndxImpl.hpp>
42 #include "../dblqh/Dblqh.hpp"
43 
44 /* **************************************************************** */
45 /* ---------------------------------------------------------------- */
46 /* ----------------------- TRIGGER HANDLING ----------------------- */
47 /* ---------------------------------------------------------------- */
48 /* **************************************************************** */
49 
50 DLList<Dbtup::TupTriggerData>*
findTriggerList(Tablerec * table,TriggerType::Value ttype,TriggerActionTime::Value ttime,TriggerEvent::Value tevent)51 Dbtup::findTriggerList(Tablerec* table,
52                        TriggerType::Value ttype,
53                        TriggerActionTime::Value ttime,
54                        TriggerEvent::Value tevent)
55 {
56   DLList<TupTriggerData>* tlist = NULL;
57   switch (ttype) {
58   case TriggerType::SUBSCRIPTION:
59   case TriggerType::SUBSCRIPTION_BEFORE:
60     switch (tevent) {
61     case TriggerEvent::TE_INSERT:
62       jam();
63       if (ttime == TriggerActionTime::TA_DETACHED)
64         tlist = &table->subscriptionInsertTriggers;
65       break;
66     case TriggerEvent::TE_UPDATE:
67       jam();
68       if (ttime == TriggerActionTime::TA_DETACHED)
69         tlist = &table->subscriptionUpdateTriggers;
70       break;
71     case TriggerEvent::TE_DELETE:
72       jam();
73       if (ttime == TriggerActionTime::TA_DETACHED)
74         tlist = &table->subscriptionDeleteTriggers;
75       break;
76     default:
77       break;
78     }
79     break;
80   case TriggerType::SECONDARY_INDEX:
81   case TriggerType::REORG_TRIGGER:
82     switch (tevent) {
83     case TriggerEvent::TE_INSERT:
84       jam();
85       if (ttime == TriggerActionTime::TA_AFTER)
86         tlist = &table->afterInsertTriggers;
87       break;
88     case TriggerEvent::TE_UPDATE:
89       jam();
90       if (ttime == TriggerActionTime::TA_AFTER)
91         tlist = &table->afterUpdateTriggers;
92       break;
93     case TriggerEvent::TE_DELETE:
94       jam();
95       if (ttime == TriggerActionTime::TA_AFTER)
96         tlist = &table->afterDeleteTriggers;
97       break;
98     default:
99       break;
100     }
101     break;
102   case TriggerType::ORDERED_INDEX:
103     switch (tevent) {
104     case TriggerEvent::TE_CUSTOM:
105       jam();
106       if (ttime == TriggerActionTime::TA_CUSTOM)
107         tlist = &table->tuxCustomTriggers;
108       break;
109     default:
110       break;
111     }
112     break;
113   case TriggerType::READ_ONLY_CONSTRAINT:
114     switch (tevent) {
115     case TriggerEvent::TE_UPDATE:
116       jam();
117       if (ttime == TriggerActionTime::TA_AFTER)
118         tlist = &table->constraintUpdateTriggers;
119       break;
120     default:
121       break;
122     }
123     break;
124   default:
125     break;
126   }
127   return tlist;
128 }
129 
130 // Trigger signals
131 void
execCREATE_TRIG_IMPL_REQ(Signal * signal)132 Dbtup::execCREATE_TRIG_IMPL_REQ(Signal* signal)
133 {
134   jamEntry();
135   if (!assembleFragments(signal))
136   {
137     jam();
138     return;
139   }
140 
141   const CreateTrigImplReq* req = (const CreateTrigImplReq*)signal->getDataPtr();
142   const Uint32 senderRef = req->senderRef;
143   const Uint32 senderData = req->senderData;
144   const Uint32 tableId = req->tableId;
145   const Uint32 triggerId = req->triggerId;
146   const Uint32 triggerInfo = req->triggerInfo;
147 
148   CreateTrigRef::ErrorCode error = CreateTrigRef::NoError;
149 
150   AttributeMask mask;
151   SectionHandle handle(this, signal);
152   if (handle.m_cnt <= CreateTrigImplReq::ATTRIBUTE_MASK_SECTION)
153   {
154     jam();
155     ndbassert(false);
156     error = CreateTrigRef::BadRequestType;
157   }
158   else
159   {
160     SegmentedSectionPtr ptr;
161     handle.getSection(ptr, CreateTrigImplReq::ATTRIBUTE_MASK_SECTION);
162     ndbrequire(ptr.sz == mask.getSizeInWords());
163     ::copy(mask.rep.data, ptr);
164   }
165 
166   releaseSections(handle);
167 
168   if (error != CreateTrigRef::NoError)
169   {
170     goto err;
171   }
172 
173   {
174     // Find table
175     TablerecPtr tabPtr;
176     tabPtr.i = req->tableId;
177     ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
178 
179     if (tabPtr.p->tableStatus != DEFINED )
180     {
181       jam();
182       error = CreateTrigRef::InvalidTable;
183     }
184     // Create trigger and associate it with the table
185     else if (createTrigger(tabPtr.p, req, mask))
186     {
187       jam();
188       // Send conf
189       CreateTrigImplConf* conf = (CreateTrigImplConf*)signal->getDataPtrSend();
190       conf->senderRef = reference();
191       conf->senderData = senderData;
192       conf->tableId = tableId;
193       conf->triggerId = triggerId;
194       conf->triggerInfo = triggerInfo;
195 
196       sendSignal(senderRef, GSN_CREATE_TRIG_IMPL_CONF,
197                  signal, CreateTrigImplConf::SignalLength, JBB);
198       return;
199     }
200     else
201     {
202       jam();
203       error = CreateTrigRef::TooManyTriggers;
204     }
205   }
206 
207 err:
208   ndbassert(error != CreateTrigRef::NoError);
209   // Send ref
210   CreateTrigImplRef* ref = (CreateTrigImplRef*)signal->getDataPtrSend();
211   ref->senderRef = reference();
212   ref->senderData = senderData;
213   ref->tableId = tableId;
214   ref->triggerId = triggerId;
215   ref->triggerInfo = triggerInfo;
216   ref->errorCode = error;
217 
218   sendSignal(senderRef, GSN_CREATE_TRIG_IMPL_REF,
219 	     signal, CreateTrigImplRef::SignalLength, JBB);
220 }
221 
222 void
execDROP_TRIG_IMPL_REQ(Signal * signal)223 Dbtup::execDROP_TRIG_IMPL_REQ(Signal* signal)
224 {
225   jamEntry();
226   const DropTrigImplReq* req = (const DropTrigImplReq*)signal->getDataPtr();
227   const Uint32 senderRef = req->senderRef;
228   const Uint32 senderData = req->senderData;
229   const Uint32 tableId = req->tableId;
230   const Uint32 indexId = req->indexId;
231   const Uint32 triggerId = req->triggerId;
232   const Uint32 triggerInfo = req->triggerInfo;
233   const Uint32 receiverRef = req->receiverRef;
234 
235   // Find table
236   TablerecPtr tabPtr;
237   tabPtr.i = req->tableId;
238   ptrCheckGuard(tabPtr, cnoOfTablerec, tablerec);
239 
240   // Drop trigger
241   Uint32 r = dropTrigger(tabPtr.p, req, refToBlock(receiverRef));
242   if (r == 0)
243   {
244     /**
245      * make sure that any trigger data is sent before DROP_TRIG_CONF
246      *   NOTE: This is only needed for SUMA triggers
247      *         (which are the only buffered ones) but it shouldn't
248      *         be too bad to do it for all triggers...
249      */
250     flush_ndbmtd_suma_buffer(signal);
251 
252     // Send conf
253     DropTrigImplConf* conf = (DropTrigImplConf*)signal->getDataPtrSend();
254     conf->senderRef = reference();
255     conf->senderData = senderData;
256     conf->tableId = tableId;
257     conf->triggerId = triggerId;
258 
259     sendSignal(senderRef, GSN_DROP_TRIG_IMPL_CONF,
260 	       signal, DropTrigImplConf::SignalLength, JBB);
261 
262     // Set ordered index to Dropping in same timeslice
263     TriggerType::Value ttype = TriggerInfo::getTriggerType(triggerInfo);
264     if (ttype == TriggerType::ORDERED_INDEX)
265     {
266       jam();
267       AlterIndxImplReq* areq = (AlterIndxImplReq*)signal->getDataPtrSend();
268       areq->senderRef = 0; // no CONF
269       areq->senderData = 0;
270       areq->requestType = AlterIndxImplReq::AlterIndexOffline;
271       areq->tableId = tableId;
272       areq->tableVersion = 0;
273       areq->indexId = indexId; // index id
274       areq->indexVersion = 0;
275       areq->indexType = DictTabInfo::OrderedIndex;
276       EXECUTE_DIRECT(DBTUX, GSN_ALTER_INDX_IMPL_REQ,
277                      signal, AlterIndxImplReq::SignalLength);
278     }
279   } else {
280     // Send ref
281     DropTrigImplRef* ref = (DropTrigImplRef*)signal->getDataPtrSend();
282     ref->senderRef = reference();
283     ref->senderData = senderData;
284     ref->tableId = tableId;
285     ref->triggerId = triggerId;
286     ref->errorCode = r;
287     sendSignal(senderRef, GSN_DROP_TRIG_IMPL_REF,
288 	       signal, DropTrigImplRef::SignalLength, JBB);
289   }
290 }
291 
292 /* ---------------------------------------------------------------- */
293 /* ------------------------- createTrigger ------------------------ */
294 /*                                                                  */
295 /* Creates a new trigger record by fetching one from the trigger    */
296 /* pool and associates it with the given table.                     */
297 /* Trigger type can be one of secondary_index, subscription,        */
298 /* constraint(NYI), foreign_key(NYI), schema_upgrade(NYI),          */
299 /* api_trigger(NYI) or sql_trigger(NYI).                            */
300 /* Note that this method only checks for total number of allowed    */
301 /* triggers. Checking the number of allowed triggers per table is   */
302 /* done by TRIX.                                                    */
303 /*                                                                  */
304 /* ---------------------------------------------------------------- */
305 bool
createTrigger(Tablerec * table,const CreateTrigImplReq * req,const AttributeMask & mask)306 Dbtup::createTrigger(Tablerec* table,
307                      const CreateTrigImplReq* req,
308                      const AttributeMask& mask)
309 {
310   if (ERROR_INSERTED(4003)) {
311     CLEAR_ERROR_INSERT_VALUE;
312     return false;
313   }
314 
315   const Uint32 tinfo = req->triggerInfo;
316   TriggerType::Value ttype = TriggerInfo::getTriggerType(tinfo);
317   TriggerActionTime::Value ttime = TriggerInfo::getTriggerActionTime(tinfo);
318   TriggerEvent::Value tevent = TriggerInfo::getTriggerEvent(tinfo);
319 
320   int cnt;
321   struct {
322     TriggerEvent::Value event;
323     DLList<TupTriggerData> * list;
324     TriggerPtr ptr;
325   } tmp[3];
326 
327   if (ttype == TriggerType::SECONDARY_INDEX ||
328       ttype == TriggerType::REORG_TRIGGER)
329   {
330     jam();
331     cnt = 3;
332     tmp[0].event = TriggerEvent::TE_INSERT;
333     tmp[1].event = TriggerEvent::TE_UPDATE;
334     tmp[2].event = TriggerEvent::TE_DELETE;
335   }
336   else
337   {
338     jam();
339     cnt = 1;
340     tmp[0].event = tevent;
341   }
342 
343   int i = 0;
344   for (i = 0; i<cnt; i++)
345   {
346     tmp[i].list = findTriggerList(table, ttype, ttime, tmp[i].event);
347     ndbrequire(tmp[i].list != NULL);
348 
349     TriggerPtr tptr;
350     if (!tmp[i].list->seize(tptr))
351     {
352       jam();
353       goto err;
354     }
355 
356     tmp[i].ptr = tptr;
357 
358     // Set trigger id
359     tptr.p->triggerId = req->triggerId;
360     tptr.p->oldTriggerIds[0] = req->upgradeExtra[0];
361     tptr.p->oldTriggerIds[1] = req->upgradeExtra[1];
362     tptr.p->oldTriggerIds[2] = req->upgradeExtra[2];
363 
364     // Set index id
365     tptr.p->indexId = req->indexId;
366 
367     // Set trigger type etc
368     tptr.p->triggerType = ttype;
369     tptr.p->triggerActionTime = ttime;
370     tptr.p->triggerEvent = tevent;
371 
372     tptr.p->sendBeforeValues = true;
373     if ((tptr.p->triggerType == TriggerType::SUBSCRIPTION) &&
374 	((tptr.p->triggerEvent == TriggerEvent::TE_UPDATE) ||
375 	 (tptr.p->triggerEvent == TriggerEvent::TE_DELETE))) {
376       jam();
377       tptr.p->sendBeforeValues = false;
378     }
379 
380     if (ttype == TriggerType::REORG_TRIGGER)
381     {
382       jam();
383       tptr.p->sendBeforeValues = false;
384     }
385 
386     /*
387       tptr.p->sendOnlyChangedAttributes = false;
388       if (((tptr.p->triggerType == TriggerType::SUBSCRIPTION) ||
389       (tptr.p->triggerType == TriggerType::SUBSCRIPTION_BEFORE)) &&
390       (tptr.p->triggerEvent == TriggerEvent::TE_UPDATE)) {
391       jam();
392       tptr.p->sendOnlyChangedAttributes = true;
393       }
394     */
395     tptr.p->sendOnlyChangedAttributes =
396       !TriggerInfo::getReportAllMonitoredAttributes(tinfo);
397 
398     tptr.p->monitorAllAttributes = TriggerInfo::getMonitorAllAttributes(tinfo);
399     tptr.p->monitorReplicas = TriggerInfo::getMonitorReplicas(tinfo);
400     tptr.p->m_receiverRef = req->receiverRef;
401 
402     if (tptr.p->monitorAllAttributes)
403     {
404       jam();
405       // Set all non-pk attributes
406       tptr.p->attributeMask.set();
407       for(Uint32 i = 0; i < table->m_no_of_attributes; i++) {
408 	if (primaryKey(table, i))
409 	  tptr.p->attributeMask.clear(i);
410       }
411     }
412     else
413     {
414       jam();
415       // Set attribute mask
416       tptr.p->attributeMask = mask;
417     }
418   }
419   return true;
420 
421 err:
422   for (--i; i >= 0; i--)
423   {
424     jam();
425     tmp[i].list->release(tmp[i].ptr);
426   }
427   return false;
428 }//Dbtup::createTrigger()
429 
430 bool
primaryKey(Tablerec * const regTabPtr,Uint32 attrId)431 Dbtup::primaryKey(Tablerec* const regTabPtr, Uint32 attrId)
432 {
433   Uint32 attrDescriptorStart = regTabPtr->tabDescriptor;
434   Uint32 attrDescriptor = getTabDescrWord(attrDescriptorStart +
435                                           (attrId * ZAD_SIZE));
436   return (bool)AttributeDescriptor::getPrimaryKey(attrDescriptor);
437 }//Dbtup::primaryKey()
438 
439 /* ---------------------------------------------------------------- */
440 /* -------------------------- dropTrigger ------------------------- */
441 /*                                                                  */
442 /* Deletes a trigger record by disassociating it with the given     */
443 /* table and returning it to the trigger pool.                      */
444 /* Trigger type can be one of secondary_index, subscription,        */
445 /* constraint(NYI), foreign_key(NYI), schema_upgrade(NYI),          */
446 /* api_trigger(NYI) or sql_trigger(NYI).                            */
447 /*                                                                  */
448 /* ---------------------------------------------------------------- */
449 Uint32
dropTrigger(Tablerec * table,const DropTrigImplReq * req,BlockNumber receiver)450 Dbtup::dropTrigger(Tablerec* table, const DropTrigImplReq* req, BlockNumber receiver)
451 {
452   if (ERROR_INSERTED(4004)) {
453     CLEAR_ERROR_INSERT_VALUE;
454     return 9999;
455   }
456   Uint32 triggerId = req->triggerId;
457 
458   const Uint32 tinfo = req->triggerInfo;
459   TriggerType::Value ttype = TriggerInfo::getTriggerType(tinfo);
460   TriggerActionTime::Value ttime = TriggerInfo::getTriggerActionTime(tinfo);
461   TriggerEvent::Value tevent = TriggerInfo::getTriggerEvent(tinfo);
462 
463   //  ndbout_c("Drop TupTrigger %u = %u %u %u %u by %u", triggerId, table, ttype, ttime, tevent, sender);
464 
465   int cnt;
466   struct {
467     TriggerEvent::Value event;
468     DLList<TupTriggerData> * list;
469     TriggerPtr ptr;
470   } tmp[3];
471 
472   if (ttype == TriggerType::SECONDARY_INDEX ||
473       ttype == TriggerType::REORG_TRIGGER)
474   {
475     jam();
476     cnt = 3;
477     tmp[0].event = TriggerEvent::TE_INSERT;
478     tmp[1].event = TriggerEvent::TE_UPDATE;
479     tmp[2].event = TriggerEvent::TE_DELETE;
480   }
481   else
482   {
483     jam();
484     cnt = 1;
485     tmp[0].event = tevent;
486   }
487 
488   int i = 0;
489   for (i = 0; i<cnt; i++)
490   {
491     tmp[i].list = findTriggerList(table, ttype, ttime, tmp[i].event);
492     ndbrequire(tmp[i].list != NULL);
493 
494     Ptr<TupTriggerData> ptr;
495     tmp[i].ptr.setNull();
496     for (tmp[i].list->first(ptr); !ptr.isNull(); tmp[i].list->next(ptr))
497     {
498       jam();
499       if (ptr.p->triggerId == triggerId)
500       {
501 	if(ttype==TriggerType::SUBSCRIPTION &&
502 	   receiver != refToBlock(ptr.p->m_receiverRef))
503 	{
504 	  /**
505 	   * You can only drop your own triggers for subscription triggers.
506 	   * Trigger IDs are private for each block.
507 	   *
508 	   * SUMA encodes information in the triggerId
509 	   *
510 	   * Backup doesn't really care about the Ids though.
511 	   */
512 	  jam();
513 	  continue;
514 	}
515 	jam();
516 	tmp[i].ptr = ptr;
517       }
518     }
519     if (tmp[i].ptr.isNull())
520     {
521       jam();
522       return DropTrigRef::TriggerNotFound;
523     }
524   }
525 
526   for (i = 0; i<cnt; i++)
527   {
528     jam();
529     tmp[i].list->release(tmp[i].ptr);
530   }
531   return 0;
532 }//Dbtup::dropTrigger()
533 
534 void
execFIRE_TRIG_REQ(Signal * signal)535 Dbtup::execFIRE_TRIG_REQ(Signal* signal)
536 {
537   jam();
538   Uint32 opPtrI = signal->theData[0];
539   Uint32 pass = signal->theData[5];
540 
541   FragrecordPtr regFragPtr;
542   OperationrecPtr regOperPtr;
543   TablerecPtr regTabPtr;
544   KeyReqStruct req_struct(this, (When)(KRS_PRE_COMMIT0 + pass));
545 
546   regOperPtr.i = opPtrI;
547 
548   jamEntry();
549 
550   c_operation_pool.getPtr(regOperPtr);
551 
552   regFragPtr.i = regOperPtr.p->fragmentPtr;
553   Uint32 no_of_fragrec = cnoOfFragrec;
554   ptrCheckGuard(regFragPtr, no_of_fragrec, fragrecord);
555 
556   TransState trans_state = get_trans_state(regOperPtr.p);
557   ndbrequire(trans_state == TRANS_STARTED);
558 
559   Uint32 no_of_tablerec = cnoOfTablerec;
560   regTabPtr.i = regFragPtr.p->fragTableId;
561   ptrCheckGuard(regTabPtr, no_of_tablerec, tablerec);
562 
563   req_struct.signal = signal;
564   req_struct.TC_ref = signal->theData[1];
565   req_struct.TC_index = signal->theData[2];
566   req_struct.trans_id1 = signal->theData[3];
567   req_struct.trans_id2 = signal->theData[4];
568 
569   PagePtr page;
570   Tuple_header* tuple_ptr = (Tuple_header*)
571     get_ptr(&page, &regOperPtr.p->m_tuple_location, regTabPtr.p);
572   req_struct.m_tuple_ptr = tuple_ptr;
573 
574   OperationrecPtr lastOperPtr;
575   lastOperPtr.i = tuple_ptr->m_operation_ptr_i;
576   c_operation_pool.getPtr(lastOperPtr);
577 
578   /**
579    * Deferred triggers should fire only once per primary key (per pass)
580    *   regardless of no of DML on that primary key
581    *
582    * We keep track of this on *last* operation (which btw, implies that
583    *   a trigger can't update "own" tuple...i.e first op would be better...)
584    *
585    */
586   if (!c_lqh->check_fire_trig_pass(lastOperPtr.p->userpointer, pass))
587   {
588     jam();
589     signal->theData[0] = 0;
590     signal->theData[1] = 0;
591     return;
592   }
593 
594   /**
595    * This is deferred triggers...
596    *   which is basically the same as detached,
597    *     i.e before value is <before transaction>
598    *     and after values is <after transaction>
599    *   with the difference that they execute (fire) while
600    *   still having a transaction context...
601    *   i.e can abort transactions, modify transaction
602    */
603   req_struct.no_fired_triggers = 0;
604 
605   /**
606    * See DbtupCommit re "Setting the op-list has this effect"
607    */
608   Uint32 save[2] = { lastOperPtr.p->nextActiveOp, lastOperPtr.p->prevActiveOp };
609   lastOperPtr.p->nextActiveOp = RNIL;
610   lastOperPtr.p->prevActiveOp = RNIL;
611 
612   checkDeferredTriggers(&req_struct, lastOperPtr.p, regTabPtr.p, false);
613 
614   lastOperPtr.p->nextActiveOp = save[0];
615   lastOperPtr.p->prevActiveOp = save[1];
616 
617   signal->theData[0] = 0;
618   signal->theData[1] = req_struct.no_fired_triggers;
619 }
620 
621 /* ---------------------------------------------------------------- */
622 /* -------------- checkImmediateTriggersAfterOp ------------------ */
623 /*                                                                  */
624 /* Called after an insert, delete, or update operation takes        */
625 /* place. Fetches before tuple for deletes and updates and          */
626 /* after tuple for inserts and updates.                             */
627 /* Executes immediate triggers by sending FIRETRIGORD               */
628 /*                                                                  */
629 /* ---------------------------------------------------------------- */
630 void
checkImmediateTriggersAfterInsert(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)631 Dbtup::checkImmediateTriggersAfterInsert(KeyReqStruct *req_struct,
632                                          Operationrec *regOperPtr,
633                                          Tablerec *regTablePtr,
634                                          bool disk)
635 {
636   if (refToMain(req_struct->TC_ref) != DBTC) {
637     return;
638   }
639 
640   if (regOperPtr->op_struct.primary_replica)
641   {
642     if (! regTablePtr->afterInsertTriggers.isEmpty())
643     {
644       jam();
645       fireImmediateTriggers(req_struct,
646                             regTablePtr->afterInsertTriggers,
647                             regOperPtr,
648                             disk);
649     }
650 
651     if (! regTablePtr->deferredInsertTriggers.isEmpty())
652     {
653       checkDeferredTriggersDuringPrepare(req_struct,
654                                          regTablePtr->deferredInsertTriggers,
655                                          regOperPtr,
656                                          disk);
657     }
658   }
659 }
660 
661 void
checkImmediateTriggersAfterUpdate(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)662 Dbtup::checkImmediateTriggersAfterUpdate(KeyReqStruct *req_struct,
663                                          Operationrec* regOperPtr,
664                                          Tablerec* regTablePtr,
665                                          bool disk)
666 {
667   if (refToMain(req_struct->TC_ref) != DBTC) {
668     return;
669   }
670 
671   if (regOperPtr->op_struct.primary_replica)
672   {
673     if (! regTablePtr->afterUpdateTriggers.isEmpty())
674     {
675       jam();
676       fireImmediateTriggers(req_struct,
677                             regTablePtr->afterUpdateTriggers,
678                             regOperPtr,
679                             disk);
680     }
681 
682     if (! regTablePtr->constraintUpdateTriggers.isEmpty())
683     {
684       jam();
685       fireImmediateTriggers(req_struct,
686                             regTablePtr->constraintUpdateTriggers,
687                             regOperPtr,
688                             disk);
689     }
690 
691     if (! regTablePtr->deferredUpdateTriggers.isEmpty())
692     {
693       jam();
694       checkDeferredTriggersDuringPrepare(req_struct,
695                                          regTablePtr->deferredUpdateTriggers,
696                                          regOperPtr,
697                                          disk);
698     }
699   }
700 }
701 
702 void
checkImmediateTriggersAfterDelete(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)703 Dbtup::checkImmediateTriggersAfterDelete(KeyReqStruct *req_struct,
704                                          Operationrec* regOperPtr,
705                                          Tablerec* regTablePtr,
706                                          bool disk)
707 {
708   if (refToMain(req_struct->TC_ref) != DBTC) {
709     return;
710   }
711 
712   if (regOperPtr->op_struct.primary_replica)
713   {
714     if (! regTablePtr->afterDeleteTriggers.isEmpty())
715     {
716       fireImmediateTriggers(req_struct,
717                             regTablePtr->afterDeleteTriggers,
718                             regOperPtr,
719                             disk);
720     }
721 
722     if (! regTablePtr->deferredDeleteTriggers.isEmpty())
723     {
724       checkDeferredTriggersDuringPrepare(req_struct,
725                                          regTablePtr->deferredDeleteTriggers,
726                                          regOperPtr,
727                                          disk);
728     }
729   }
730 }
731 
732 void
checkDeferredTriggersDuringPrepare(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)733 Dbtup::checkDeferredTriggersDuringPrepare(KeyReqStruct *req_struct,
734                                           DLList<TupTriggerData>& triggerList,
735                                           Operationrec* const regOperPtr,
736                                           bool disk)
737 {
738   jam();
739   TriggerPtr trigPtr;
740   triggerList.first(trigPtr);
741   while (trigPtr.i != RNIL)
742   {
743     jam();
744     if (trigPtr.p->monitorAllAttributes ||
745         trigPtr.p->attributeMask.overlaps(req_struct->changeMask))
746     {
747       jam();
748       NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
749       return;
750     }
751   }
752 }
753 
754 /* ---------------------------------------------------------------- */
755 /* --------------------- checkDeferredTriggers -------------------- */
756 /*                                                                  */
757 /* Called before commit after an insert, delete, or update          */
758 /* operation. Fetches before tuple for deletes and updates and      */
759 /* after tuple for inserts and updates.                             */
760 /* Executes deferred triggers by sending FIRETRIGORD                */
761 /*                                                                  */
762 /* ---------------------------------------------------------------- */
checkDeferredTriggers(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)763 void Dbtup::checkDeferredTriggers(KeyReqStruct *req_struct,
764                                   Operationrec* regOperPtr,
765                                   Tablerec* regTablePtr,
766                                   bool disk)
767 {
768   jam();
769   Uint32 save_type = regOperPtr->op_struct.op_type;
770   Tuple_header *save_ptr = req_struct->m_tuple_ptr;
771   DLList<TupTriggerData> * deferred_list = 0;
772   DLList<TupTriggerData> * constraint_list = 0;
773 
774   switch (save_type) {
775   case ZUPDATE:
776   case ZINSERT:
777     req_struct->m_tuple_ptr =get_copy_tuple(&regOperPtr->m_copy_tuple_location);
778     break;
779   }
780 
781   /**
782    * Set correct operation type and fix change mask
783    * Note ALLOC is set in "orig" tuple
784    */
785   if (save_ptr->m_header_bits & Tuple_header::ALLOC) {
786     if (save_type == ZDELETE) {
787       // insert + delete = nothing
788       jam();
789       return;
790       goto end;
791     }
792     regOperPtr->op_struct.op_type = ZINSERT;
793   }
794   else if (save_type == ZINSERT) {
795     /**
796      * Tuple was not created but last op is INSERT.
797      * This is possible only on DELETE + INSERT
798      */
799     regOperPtr->op_struct.op_type = ZUPDATE;
800   }
801 
802   switch(regOperPtr->op_struct.op_type) {
803   case(ZINSERT):
804     jam();
805     deferred_list = &regTablePtr->deferredInsertTriggers;
806     constraint_list = &regTablePtr->afterInsertTriggers;
807     break;
808   case(ZDELETE):
809     jam();
810     deferred_list = &regTablePtr->deferredDeleteTriggers;
811     constraint_list = &regTablePtr->afterDeleteTriggers;
812     break;
813   case(ZUPDATE):
814     jam();
815     deferred_list = &regTablePtr->deferredUpdateTriggers;
816     constraint_list = &regTablePtr->afterUpdateTriggers;
817     break;
818   default:
819     ndbrequire(false);
820     break;
821   }
822 
823   if (req_struct->m_deferred_constraints == false)
824   {
825     constraint_list = 0;
826   }
827 
828   if (deferred_list->isEmpty() &&
829       (constraint_list == 0 || constraint_list->isEmpty()))
830   {
831     goto end;
832   }
833 
834   /**
835    * Compute change-mask
836    */
837   set_commit_change_mask_info(regTablePtr, req_struct, regOperPtr);
838   if (!deferred_list->isEmpty())
839   {
840     fireDeferredTriggers(req_struct, * deferred_list, regOperPtr, disk);
841   }
842 
843   if (constraint_list && !constraint_list->isEmpty())
844   {
845     fireDeferredConstraints(req_struct, * constraint_list, regOperPtr, disk);
846   }
847 
848 end:
849   regOperPtr->op_struct.op_type = save_type;
850   req_struct->m_tuple_ptr = save_ptr;
851 }//Dbtup::checkDeferredTriggers()
852 
853 /* ---------------------------------------------------------------- */
854 /* --------------------- checkDetachedTriggers -------------------- */
855 /*                                                                  */
856 /* Called at commit after an insert, delete, or update operation.   */
857 /* Fetches before tuple for deletes and updates and                 */
858 /* after tuple for inserts and updates.                             */
859 /* Executes detached triggers by sending FIRETRIGORD                */
860 /*                                                                  */
861 /* ---------------------------------------------------------------- */
checkDetachedTriggers(KeyReqStruct * req_struct,Operationrec * regOperPtr,Tablerec * regTablePtr,bool disk)862 void Dbtup::checkDetachedTriggers(KeyReqStruct *req_struct,
863                                   Operationrec* regOperPtr,
864                                   Tablerec* regTablePtr,
865                                   bool disk)
866 {
867   Uint32 save_type = regOperPtr->op_struct.op_type;
868   Tuple_header *save_ptr = req_struct->m_tuple_ptr;
869 
870   switch (save_type) {
871   case ZUPDATE:
872   case ZINSERT:
873   case ZREFRESH:
874     req_struct->m_tuple_ptr =get_copy_tuple(&regOperPtr->m_copy_tuple_location);
875     break;
876   }
877 
878   /**
879    * Set correct operation type and fix change mask
880    * Note ALLOC is set in "orig" tuple
881    */
882   if (save_ptr->m_header_bits & Tuple_header::ALLOC) {
883     if (save_type == ZDELETE) {
884       // insert + delete = nothing
885       jam();
886       return;
887       goto end;
888     }
889     else if (save_type != ZREFRESH)
890     {
891       regOperPtr->op_struct.op_type = ZINSERT;
892     }
893   }
894   else if (save_type == ZINSERT) {
895     /**
896      * Tuple was not created but last op is INSERT.
897      * This is possible only on DELETE + INSERT
898      */
899     regOperPtr->op_struct.op_type = ZUPDATE;
900   }
901 
902   switch(regOperPtr->op_struct.op_type) {
903   case(ZINSERT):
904     jam();
905     if (regTablePtr->subscriptionInsertTriggers.isEmpty()) {
906       // Table has no active triggers monitoring inserts at commit
907       jam();
908       goto end;
909     }
910 
911     // If any fired immediate insert trigger then fetch after tuple
912     fireDetachedTriggers(req_struct,
913                          regTablePtr->subscriptionInsertTriggers,
914                          regOperPtr, disk);
915     break;
916   case(ZDELETE):
917     jam();
918     if (regTablePtr->subscriptionDeleteTriggers.isEmpty()) {
919       // Table has no active triggers monitoring deletes at commit
920       jam();
921       goto end;
922     }
923 
924     // Execute any after delete triggers by sending
925     // FIRETRIGORD with the before tuple
926     fireDetachedTriggers(req_struct,
927 			 regTablePtr->subscriptionDeleteTriggers,
928 			 regOperPtr, disk);
929     break;
930   case(ZUPDATE):
931     jam();
932     if (regTablePtr->subscriptionUpdateTriggers.isEmpty()) {
933       // Table has no active triggers monitoring updates at commit
934       jam();
935       goto end;
936     }
937 
938     // If any fired immediate update trigger then fetch after tuple
939     // and send two FIRETRIGORD one with before tuple and one with after tuple
940     fireDetachedTriggers(req_struct,
941                          regTablePtr->subscriptionUpdateTriggers,
942                          regOperPtr, disk);
943     break;
944   case ZREFRESH:
945     jam();
946     /* Depending on the Refresh scenario, fire Delete or Insert
947      * triggers to simulate the effect of arriving at the tuple's
948      * current state.
949      */
950     switch(regOperPtr->m_copy_tuple_location.m_file_no){
951     case Operationrec::RF_SINGLE_NOT_EXIST:
952     case Operationrec::RF_MULTI_NOT_EXIST:
953       fireDetachedTriggers(req_struct,
954                            regTablePtr->subscriptionDeleteTriggers,
955                            regOperPtr, disk);
956       break;
957     case Operationrec::RF_SINGLE_EXIST:
958     case Operationrec::RF_MULTI_EXIST:
959       fireDetachedTriggers(req_struct,
960                            regTablePtr->subscriptionInsertTriggers,
961                            regOperPtr, disk);
962       break;
963     default:
964       ndbrequire(false);
965     }
966     break;
967   default:
968     ndbrequire(false);
969     break;
970   }
971 
972 end:
973   regOperPtr->op_struct.op_type = save_type;
974   req_struct->m_tuple_ptr = save_ptr;
975 }
976 
977 static
978 bool
is_constraint(const Dbtup::TupTriggerData * trigPtr)979 is_constraint(const Dbtup::TupTriggerData * trigPtr)
980 {
981   return trigPtr->triggerType == TriggerType::SECONDARY_INDEX;
982 }
983 
984 void
fireImmediateTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)985 Dbtup::fireImmediateTriggers(KeyReqStruct *req_struct,
986                              DLList<TupTriggerData>& triggerList,
987                              Operationrec* const regOperPtr,
988                              bool disk)
989 {
990   TriggerPtr trigPtr;
991   triggerList.first(trigPtr);
992   while (trigPtr.i != RNIL) {
993     jam();
994     if (trigPtr.p->monitorAllAttributes ||
995         trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
996       jam();
997 
998       if (req_struct->m_when == KRS_PREPARE &&
999           req_struct->m_deferred_constraints &&
1000           is_constraint(trigPtr.p))
1001       {
1002         NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
1003       }
1004       else
1005       {
1006         executeTrigger(req_struct,
1007                        trigPtr.p,
1008                        regOperPtr,
1009                        disk);
1010       }
1011     }
1012     triggerList.next(trigPtr);
1013   }//while
1014 }//Dbtup::fireImmediateTriggers()
1015 
1016 void
fireDeferredConstraints(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)1017 Dbtup::fireDeferredConstraints(KeyReqStruct *req_struct,
1018                                DLList<TupTriggerData>& triggerList,
1019                                Operationrec* const regOperPtr,
1020                                bool disk)
1021 {
1022   TriggerPtr trigPtr;
1023   triggerList.first(trigPtr);
1024   while (trigPtr.i != RNIL) {
1025     jam();
1026     if (trigPtr.p->monitorAllAttributes ||
1027         trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
1028       jam();
1029       executeTrigger(req_struct,
1030                      trigPtr.p,
1031                      regOperPtr,
1032                      disk);
1033     }//if
1034     triggerList.next(trigPtr);
1035   }//while
1036 }//Dbtup::fireDeferredTriggers()
1037 
1038 void
fireDeferredTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)1039 Dbtup::fireDeferredTriggers(KeyReqStruct *req_struct,
1040                             DLList<TupTriggerData>& triggerList,
1041                             Operationrec* const regOperPtr,
1042                             bool disk)
1043 {
1044   TriggerPtr trigPtr;
1045   triggerList.first(trigPtr);
1046   while (trigPtr.i != RNIL) {
1047     jam();
1048     if (trigPtr.p->monitorAllAttributes ||
1049         trigPtr.p->attributeMask.overlaps(req_struct->changeMask)) {
1050       jam();
1051       executeTrigger(req_struct,
1052                      trigPtr.p,
1053                      regOperPtr,
1054                      disk);
1055     }//if
1056     triggerList.next(trigPtr);
1057   }//while
1058 }//Dbtup::fireDeferredTriggers()
1059 
1060 void
fireDetachedTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * const regOperPtr,bool disk)1061 Dbtup::fireDetachedTriggers(KeyReqStruct *req_struct,
1062                             DLList<TupTriggerData>& triggerList,
1063                             Operationrec* const regOperPtr,
1064                             bool disk)
1065 {
1066 
1067   TriggerPtr trigPtr;
1068 
1069   /**
1070    * Set disk page
1071    */
1072   req_struct->m_disk_page_ptr.i = m_pgman_ptr.i;
1073 
1074   ndbrequire(regOperPtr->is_first_operation());
1075   triggerList.first(trigPtr);
1076   while (trigPtr.i != RNIL) {
1077     jam();
1078     if ((trigPtr.p->monitorReplicas ||
1079          regOperPtr->op_struct.primary_replica) &&
1080         (trigPtr.p->monitorAllAttributes ||
1081          trigPtr.p->attributeMask.overlaps(req_struct->changeMask))) {
1082       jam();
1083       executeTrigger(req_struct,
1084                      trigPtr.p,
1085                      regOperPtr,
1086                      disk);
1087     }
1088     triggerList.next(trigPtr);
1089   }
1090 }
1091 
executeTriggers(KeyReqStruct * req_struct,DLList<TupTriggerData> & triggerList,Operationrec * regOperPtr,bool disk)1092 void Dbtup::executeTriggers(KeyReqStruct *req_struct,
1093                             DLList<TupTriggerData>& triggerList,
1094                             Operationrec* regOperPtr,
1095                             bool disk)
1096 {
1097   TriggerPtr trigPtr;
1098   triggerList.first(trigPtr);
1099   while (trigPtr.i != RNIL) {
1100     jam();
1101     executeTrigger(req_struct,
1102                    trigPtr.p,
1103                    regOperPtr,
1104                    disk);
1105     triggerList.next(trigPtr);
1106 
1107   }
1108 }
1109 
1110 bool
check_fire_trigger(const Fragrecord * fragPtrP,const TupTriggerData * trigPtrP,const KeyReqStruct * req_struct,const Operationrec * regOperPtr) const1111 Dbtup::check_fire_trigger(const Fragrecord * fragPtrP,
1112                           const TupTriggerData* trigPtrP,
1113                           const KeyReqStruct * req_struct,
1114                           const Operationrec * regOperPtr) const
1115 {
1116   jam();
1117 
1118   if (trigPtrP->triggerType == TriggerType::SUBSCRIPTION_BEFORE)
1119   {
1120     if (!check_fire_suma(req_struct, regOperPtr, fragPtrP))
1121       return false;
1122     return true;
1123   }
1124 
1125   switch(fragPtrP->fragStatus){
1126   case Fragrecord::FS_REORG_NEW:
1127     jam();
1128     return false;
1129   case Fragrecord::FS_REORG_COMMIT:
1130   case Fragrecord::FS_REORG_COMPLETE:
1131     return req_struct->m_reorg == 0;
1132   default:
1133     return true;
1134   }
1135 }
1136 
1137 bool
check_fire_reorg(const KeyReqStruct * req_struct,Fragrecord::FragState state) const1138 Dbtup::check_fire_reorg(const KeyReqStruct *req_struct,
1139                         Fragrecord::FragState state) const
1140 {
1141   Uint32 flag = req_struct->m_reorg;
1142   switch(state){
1143   case Fragrecord::FS_ONLINE:
1144   case Fragrecord::FS_REORG_COMMIT_NEW:
1145   case Fragrecord::FS_REORG_COMPLETE_NEW:
1146     jam();
1147     if (flag == 2)
1148     {
1149       jam();
1150       return true;
1151     }
1152     return false;
1153   case Fragrecord::FS_REORG_NEW:
1154   case Fragrecord::FS_REORG_COMMIT:
1155   case Fragrecord::FS_REORG_COMPLETE:
1156   default:
1157     jam();
1158     return false;
1159   }
1160 }
1161 
1162 bool
check_fire_suma(const KeyReqStruct * req_struct,const Operationrec * opPtrP,const Fragrecord * regFragPtrP) const1163 Dbtup::check_fire_suma(const KeyReqStruct *req_struct,
1164                        const Operationrec* opPtrP,
1165                        const Fragrecord* regFragPtrP) const
1166 {
1167   Ptr<Tablerec> tablePtr;
1168   tablePtr.i = regFragPtrP->fragTableId;
1169   Fragrecord::FragState state = regFragPtrP->fragStatus;
1170   Uint32 gci_hi = req_struct->gci_hi;
1171   Uint32 flag = opPtrP->op_struct.m_reorg;
1172 
1173   switch(state){
1174   case Fragrecord::FS_FREE:
1175     ndbassert(false);
1176     return false;
1177   case Fragrecord::FS_ONLINE:
1178     jam();
1179     return true;
1180   case Fragrecord::FS_REORG_NEW:
1181     jam();
1182     return false;
1183   case Fragrecord::FS_REORG_COMMIT_NEW:
1184     jam();
1185     return false;
1186   case Fragrecord::FS_REORG_COMPLETE_NEW:
1187     jam();
1188     return true;
1189   case Fragrecord::FS_REORG_COMMIT:
1190     jam();
1191     return true;
1192   case Fragrecord::FS_REORG_COMPLETE:
1193     jam();
1194     if (flag != 1)
1195     {
1196       jam();
1197       return true;
1198     }
1199     break;
1200   }
1201 
1202   ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec);
1203   if (gci_hi < tablePtr.p->m_reorg_suma_filter.m_gci_hi)
1204   {
1205     jam();
1206     return true;
1207   }
1208 
1209   return false;
1210 }
1211 
1212 Uint32
getOldTriggerId(const TupTriggerData * trigPtrP,Uint32 op_type)1213 Dbtup::getOldTriggerId(const TupTriggerData* trigPtrP,
1214                        Uint32 op_type)
1215 {
1216   switch(op_type){
1217   case ZINSERT:
1218     return trigPtrP->oldTriggerIds[0];
1219   case ZUPDATE:
1220     return trigPtrP->oldTriggerIds[1];
1221   case ZDELETE:
1222     return trigPtrP->oldTriggerIds[2];
1223   }
1224   ndbrequire(false);
1225   return RNIL;
1226 }
1227 
executeTrigger(KeyReqStruct * req_struct,TupTriggerData * const trigPtr,Operationrec * const regOperPtr,bool disk)1228 void Dbtup::executeTrigger(KeyReqStruct *req_struct,
1229                            TupTriggerData* const trigPtr,
1230                            Operationrec* const regOperPtr,
1231                            bool disk)
1232 {
1233   Signal* signal= req_struct->signal;
1234   BlockReference ref = trigPtr->m_receiverRef;
1235   Uint32* const keyBuffer = &cinBuffer[0];
1236   Uint32* const afterBuffer = &coutBuffer[0];
1237   Uint32* const beforeBuffer = &clogMemBuffer[0];
1238   Uint32 triggerType = trigPtr->triggerType;
1239 
1240   Uint32 noPrimKey, noAfterWords, noBeforeWords;
1241   FragrecordPtr regFragPtr;
1242   regFragPtr.i= regOperPtr->fragmentPtr;
1243   ptrCheckGuard(regFragPtr, cnoOfFragrec, fragrecord);
1244   Fragrecord::FragState fragstatus = regFragPtr.p->fragStatus;
1245 
1246   if (refToMain(ref) == BACKUP)
1247   {
1248     jam();
1249     if (isNdbMtLqh())
1250     {
1251       goto out;
1252     }
1253 
1254     /*
1255     In order for the implementation of BACKUP to work even when changing
1256     primaries in the middle of the backup we need to set the trigger on
1257     all replicas. This check checks whether this is the node where this
1258     trigger should be fired. The check should preferably have been put
1259     completely in the BACKUP block but it was about five times simpler
1260     to put it here and also much faster for the backup (small overhead
1261     for everybody else.
1262     */
1263     signal->theData[0] = trigPtr->triggerId;
1264     signal->theData[1] = regFragPtr.p->fragmentId;
1265     EXECUTE_DIRECT(BACKUP, GSN_BACKUP_TRIG_REQ, signal, 2);
1266     jamEntry();
1267     if (signal->theData[0] == 0) {
1268       jam();
1269       return;
1270     }
1271 out:
1272     (void)1;
1273   }
1274   else if (unlikely(triggerType == TriggerType::REORG_TRIGGER))
1275   {
1276     if (!check_fire_reorg(req_struct, fragstatus))
1277       return;
1278   }
1279   else if (unlikely(regFragPtr.p->fragStatus != Fragrecord::FS_ONLINE))
1280   {
1281     if (!check_fire_trigger(regFragPtr.p, trigPtr, req_struct, regOperPtr))
1282       return;
1283   }
1284 
1285   if (!readTriggerInfo(trigPtr,
1286                        regOperPtr,
1287                        req_struct,
1288                        regFragPtr.p,
1289                        keyBuffer,
1290                        noPrimKey,
1291                        afterBuffer,
1292                        noAfterWords,
1293                        beforeBuffer,
1294                        noBeforeWords,
1295                        disk)) {
1296     jam();
1297     return;
1298   }
1299 
1300 //--------------------------------------------------------------------
1301 // Now all data for this trigger has been read. It is now time to send
1302 // the trigger information consisting of two or three sets of TRIG_
1303 // ATTRINFO signals and one FIRE_TRIG_ORD signal.
1304 // We start by setting common header info for all TRIG_ATTRINFO signals.
1305 //--------------------------------------------------------------------
1306   bool executeDirect;
1307   bool longsignal = false;
1308   Uint32 triggerId = trigPtr->triggerId;
1309   TrigAttrInfo* const trigAttrInfo = (TrigAttrInfo *)signal->getDataPtrSend();
1310   trigAttrInfo->setConnectionPtr(req_struct->TC_index);
1311   trigAttrInfo->setTriggerId(trigPtr->triggerId);
1312 
1313   switch(triggerType) {
1314   case (TriggerType::SECONDARY_INDEX):
1315   {
1316     jam();
1317     /**
1318      * Handle stupid 6.3 which uses one triggerId per operation type
1319      */
1320     Uint32 node = refToNode(req_struct->TC_ref);
1321     if (unlikely(node && getNodeInfo(node).m_version < MAKE_VERSION(6,4,0)))
1322     {
1323       jam();
1324       triggerId = getOldTriggerId(trigPtr, regOperPtr->op_struct.op_type);
1325       trigAttrInfo->setTriggerId(triggerId);
1326     }
1327     // fall-through
1328   }
1329   case (TriggerType::REORG_TRIGGER):
1330     jam();
1331     ref = req_struct->TC_ref;
1332     executeDirect = false;
1333     break;
1334   case (TriggerType::SUBSCRIPTION):
1335   case (TriggerType::SUBSCRIPTION_BEFORE):
1336     jam();
1337     // Since only backup uses subscription triggers we send to backup directly for now
1338     ref = trigPtr->m_receiverRef;
1339     // executeDirect = !isNdbMtLqh() || (refToMain(ref) != SUMA);
1340     executeDirect = refToInstance(ref) == instance();
1341 
1342     // If we can do execute direct, lets do that, else do long signal (only local node)
1343     longsignal = !executeDirect;
1344     ndbassert(refToNode(ref) == 0 || refToNode(ref) == getOwnNodeId());
1345     break;
1346   case (TriggerType::READ_ONLY_CONSTRAINT):
1347     terrorCode = ZREAD_ONLY_CONSTRAINT_VIOLATION;
1348     // XXX should return status and abort the rest
1349     return;
1350   default:
1351     ndbrequire(false);
1352     executeDirect= false; // remove warning
1353   }//switch
1354 
1355 
1356   if (ERROR_INSERTED(4030))
1357   {
1358     terrorCode = ZREAD_ONLY_CONSTRAINT_VIOLATION;
1359     // XXX should return status and abort the rest
1360     return;
1361   }
1362 
1363   if (triggerType == TriggerType::SECONDARY_INDEX &&
1364       req_struct->m_when != KRS_PREPARE)
1365   {
1366     ndbrequire(req_struct->m_deferred_constraints);
1367     if (req_struct->m_when == KRS_PRE_COMMIT0)
1368     {
1369       switch(regOperPtr->op_struct.op_type){
1370       case ZINSERT:
1371         NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
1372         return;
1373         break;
1374       case ZUPDATE:
1375         NoOfFiredTriggers::setDeferredBit(req_struct->no_fired_triggers);
1376         noAfterWords = 0;
1377         break;
1378       case ZDELETE:
1379         break;
1380       default:
1381         ndbrequire(false);
1382       }
1383     }
1384     else
1385     {
1386       ndbrequire(req_struct->m_when == KRS_PRE_COMMIT1);
1387       switch(regOperPtr->op_struct.op_type){
1388       case ZINSERT:
1389         break;
1390       case ZUPDATE:
1391         noBeforeWords = 0;
1392         break;
1393       case ZDELETE:
1394         return;
1395       default:
1396         ndbrequire(false);
1397       }
1398     }
1399   }
1400 
1401   req_struct->no_fired_triggers++;
1402 
1403   if (longsignal == false)
1404   {
1405     jam();
1406 
1407     trigAttrInfo->setAttrInfoType(TrigAttrInfo::PRIMARY_KEY);
1408     sendTrigAttrInfo(signal, keyBuffer, noPrimKey, executeDirect, ref);
1409 
1410     switch(regOperPtr->op_struct.op_type) {
1411     case(ZINSERT):
1412     is_insert:
1413       jam();
1414       // Send AttrInfo signals with new attribute values
1415       trigAttrInfo->setAttrInfoType(TrigAttrInfo::AFTER_VALUES);
1416       sendTrigAttrInfo(signal, afterBuffer, noAfterWords, executeDirect, ref);
1417       break;
1418     case(ZDELETE):
1419     is_delete:
1420       if (trigPtr->sendBeforeValues) {
1421         jam();
1422         trigAttrInfo->setAttrInfoType(TrigAttrInfo::BEFORE_VALUES);
1423         sendTrigAttrInfo(signal, beforeBuffer, noBeforeWords, executeDirect,ref);
1424       }
1425       break;
1426     case(ZUPDATE):
1427       jam();
1428       if (trigPtr->sendBeforeValues) {
1429         jam();
1430         trigAttrInfo->setAttrInfoType(TrigAttrInfo::BEFORE_VALUES);
1431         sendTrigAttrInfo(signal, beforeBuffer, noBeforeWords, executeDirect,ref);
1432       }
1433       trigAttrInfo->setAttrInfoType(TrigAttrInfo::AFTER_VALUES);
1434       sendTrigAttrInfo(signal, afterBuffer, noAfterWords, executeDirect, ref);
1435       break;
1436     case ZREFRESH:
1437       jam();
1438       /* Reuse Insert/Delete trigger firing code as necessary */
1439       switch(regOperPtr->m_copy_tuple_location.m_file_no){
1440       case Operationrec::RF_SINGLE_NOT_EXIST:
1441         jam();
1442       case Operationrec::RF_MULTI_NOT_EXIST:
1443         jam();
1444         goto is_delete;
1445       case Operationrec::RF_SINGLE_EXIST:
1446         jam();
1447       case Operationrec::RF_MULTI_EXIST:
1448         jam();
1449         goto is_insert;
1450       default:
1451         ndbrequire(false);
1452       }
1453     default:
1454       ndbrequire(false);
1455     }
1456   }
1457 
1458   /**
1459    * sendFireTrigOrd
1460    */
1461   FireTrigOrd* const fireTrigOrd = (FireTrigOrd *)signal->getDataPtrSend();
1462 
1463   fireTrigOrd->setConnectionPtr(req_struct->TC_index);
1464   fireTrigOrd->setTriggerId(triggerId);
1465   fireTrigOrd->fragId= regFragPtr.p->fragmentId;
1466 
1467   switch(regOperPtr->op_struct.op_type) {
1468   case(ZINSERT):
1469     jam();
1470     fireTrigOrd->m_triggerEvent = TriggerEvent::TE_INSERT;
1471     break;
1472   case(ZUPDATE):
1473     jam();
1474     fireTrigOrd->m_triggerEvent = TriggerEvent::TE_UPDATE;
1475     break;
1476   case(ZDELETE):
1477     jam();
1478     fireTrigOrd->m_triggerEvent = TriggerEvent::TE_DELETE;
1479     break;
1480   case ZREFRESH:
1481     jam();
1482     switch(regOperPtr->m_copy_tuple_location.m_file_no){
1483     case Operationrec::RF_SINGLE_NOT_EXIST:
1484       jam();
1485     case Operationrec::RF_MULTI_NOT_EXIST:
1486       jam();
1487       fireTrigOrd->m_triggerEvent = TriggerEvent::TE_DELETE;
1488       break;
1489     case Operationrec::RF_SINGLE_EXIST:
1490       jam();
1491     case Operationrec::RF_MULTI_EXIST:
1492       jam();
1493       fireTrigOrd->m_triggerEvent = TriggerEvent::TE_INSERT;
1494       break;
1495     default:
1496       ndbrequire(false);
1497     }
1498     break;
1499   default:
1500     ndbrequire(false);
1501     break;
1502   }
1503 
1504   fireTrigOrd->setNoOfPrimaryKeyWords(noPrimKey);
1505   fireTrigOrd->setNoOfBeforeValueWords(noBeforeWords);
1506   fireTrigOrd->setNoOfAfterValueWords(noAfterWords);
1507 
1508   switch(trigPtr->triggerType) {
1509   case (TriggerType::SECONDARY_INDEX):
1510   case (TriggerType::REORG_TRIGGER):
1511     jam();
1512     fireTrigOrd->m_triggerType = trigPtr->triggerType;
1513     fireTrigOrd->m_transId1 = req_struct->trans_id1;
1514     fireTrigOrd->m_transId2 = req_struct->trans_id2;
1515     sendSignal(req_struct->TC_ref, GSN_FIRE_TRIG_ORD,
1516                signal, FireTrigOrd::SignalLength, JBB);
1517     break;
1518   case (TriggerType::SUBSCRIPTION_BEFORE): // Only Suma
1519     jam();
1520     fireTrigOrd->m_transId1 = req_struct->trans_id1;
1521     fireTrigOrd->m_transId2 = req_struct->trans_id2;
1522     fireTrigOrd->setGCI(req_struct->gci_hi);
1523     fireTrigOrd->setHashValue(req_struct->hash_value);
1524     fireTrigOrd->m_any_value = regOperPtr->m_any_value;
1525     fireTrigOrd->m_gci_lo = req_struct->gci_lo;
1526     if (executeDirect)
1527     {
1528       jam();
1529       EXECUTE_DIRECT(refToMain(ref),
1530                      GSN_FIRE_TRIG_ORD,
1531                      signal,
1532                      FireTrigOrd::SignalLengthSuma);
1533       jamEntry();
1534     }
1535     else
1536     {
1537       ndbassert(longsignal);
1538       LinearSectionPtr ptr[3];
1539       ptr[0].p = keyBuffer;
1540       ptr[0].sz = noPrimKey;
1541       ptr[1].p = beforeBuffer;
1542       ptr[1].sz = noBeforeWords;
1543       ptr[2].p = afterBuffer;
1544       ptr[2].sz = noAfterWords;
1545       if (refToMain(ref) == SUMA && (refToInstance(ref) != instance()))
1546       {
1547         jam();
1548         ndbmtd_buffer_suma_trigger(signal, FireTrigOrd::SignalLengthSuma, ptr);
1549       }
1550       else
1551       {
1552         jam();
1553         sendSignal(ref, GSN_FIRE_TRIG_ORD,
1554                    signal, FireTrigOrd::SignalLengthSuma, JBB, ptr, 3);
1555       }
1556     }
1557     break;
1558   case (TriggerType::SUBSCRIPTION):
1559     jam();
1560     // Since only backup uses subscription triggers we
1561     // send to backup directly for now
1562     fireTrigOrd->setGCI(req_struct->gci_hi);
1563 
1564     if (executeDirect)
1565     {
1566       jam();
1567       EXECUTE_DIRECT(refToMain(ref),
1568                      GSN_FIRE_TRIG_ORD,
1569                      signal,
1570                      FireTrigOrd::SignalWithGCILength);
1571       jamEntry();
1572     }
1573     else
1574     {
1575       jam();
1576       // Todo send onlu before/after depending on BACKUP REDO/UNDO
1577       ndbassert(longsignal);
1578       LinearSectionPtr ptr[3];
1579       ptr[0].p = keyBuffer;
1580       ptr[0].sz = noPrimKey;
1581       ptr[1].p = beforeBuffer;
1582       ptr[1].sz = noBeforeWords;
1583       ptr[2].p = afterBuffer;
1584       ptr[2].sz = noAfterWords;
1585       sendSignal(ref, GSN_FIRE_TRIG_ORD,
1586                  signal, FireTrigOrd::SignalWithGCILength, JBB, ptr, 3);
1587     }
1588     break;
1589   default:
1590     ndbrequire(false);
1591     break;
1592   }
1593 }
1594 
setAttrIds(Bitmask<MAXNROFATTRIBUTESINWORDS> & attributeMask,Uint32 m_no_of_attributesibutes,Uint32 * inBuffer)1595 Uint32 Dbtup::setAttrIds(Bitmask<MAXNROFATTRIBUTESINWORDS>& attributeMask,
1596                          Uint32 m_no_of_attributesibutes,
1597                          Uint32* inBuffer)
1598 {
1599   Uint32 bufIndx = 0;
1600   for (Uint32 i = 0; i < m_no_of_attributesibutes; i++) {
1601     jam();
1602     if (attributeMask.get(i)) {
1603       jam();
1604       AttributeHeader::init(&inBuffer[bufIndx++], i, 0);
1605     }
1606   }
1607   return bufIndx;
1608 }
1609 
readTriggerInfo(TupTriggerData * const trigPtr,Operationrec * const regOperPtr,KeyReqStruct * req_struct,Fragrecord * const regFragPtr,Uint32 * const keyBuffer,Uint32 & noPrimKey,Uint32 * const afterBuffer,Uint32 & noAfterWords,Uint32 * const beforeBuffer,Uint32 & noBeforeWords,bool disk)1610 bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr,
1611                             Operationrec* const regOperPtr,
1612                             KeyReqStruct *req_struct,
1613                             Fragrecord* const regFragPtr,
1614                             Uint32* const keyBuffer,
1615                             Uint32& noPrimKey,
1616                             Uint32* const afterBuffer,
1617                             Uint32& noAfterWords,
1618                             Uint32* const beforeBuffer,
1619                             Uint32& noBeforeWords,
1620                             bool disk)
1621 {
1622   noAfterWords = 0;
1623   noBeforeWords = 0;
1624   Uint32 readBuffer[MAX_ATTRIBUTES_IN_TABLE];
1625 
1626 //---------------------------------------------------------------------------
1627 // Set-up variables needed by readAttributes operPtr.p, tabptr.p
1628 //---------------------------------------------------------------------------
1629   Ptr<Tablerec> tabptr;
1630   Ptr<Operationrec> operPtr;
1631   operPtr.p = regOperPtr;
1632   tabptr.i = regFragPtr->fragTableId;
1633   ptrCheckGuard(tabptr, cnoOfTablerec, tablerec);
1634 
1635   Tablerec* const regTabPtr = tabptr.p;
1636   Uint32 num_attr= regTabPtr->m_no_of_attributes;
1637   Uint32 descr_start= regTabPtr->tabDescriptor;
1638   ndbrequire(descr_start + (num_attr << ZAD_LOG_SIZE) <= cnoOfTabDescrRec);
1639 
1640   req_struct->tablePtrP = regTabPtr;
1641   req_struct->operPtrP = regOperPtr;
1642   req_struct->check_offset[MM]= regTabPtr->get_check_offset(MM);
1643   req_struct->check_offset[DD]= regTabPtr->get_check_offset(DD);
1644   req_struct->attr_descr= &tableDescriptor[descr_start];
1645 
1646 //--------------------------------------------------------------------
1647 // Read Primary Key Values
1648 //--------------------------------------------------------------------
1649   Tuple_header *save0= req_struct->m_tuple_ptr;
1650   if (regOperPtr->op_struct.op_type == ZDELETE &&
1651       !regOperPtr->is_first_operation())
1652   {
1653     jam();
1654     req_struct->m_tuple_ptr=
1655       get_copy_tuple(&req_struct->prevOpPtr.p->m_copy_tuple_location);
1656   }
1657 
1658   if (regTabPtr->need_expand(disk))
1659     prepare_read(req_struct, regTabPtr, disk);
1660 
1661   int ret = readAttributes(req_struct,
1662 			   &tableDescriptor[regTabPtr->readKeyArray].tabDescr,
1663 			   regTabPtr->noOfKeyAttr,
1664 			   keyBuffer,
1665 			   ZATTR_BUFFER_SIZE,
1666 			   false);
1667   ndbrequire(ret >= 0);
1668   noPrimKey= ret;
1669 
1670   req_struct->m_tuple_ptr = save0;
1671 
1672   Uint32 numAttrsToRead;
1673   if ((regOperPtr->op_struct.op_type == ZUPDATE) &&
1674       (trigPtr->sendOnlyChangedAttributes)) {
1675     jam();
1676 //--------------------------------------------------------------------
1677 // Update that sends only changed information
1678 //--------------------------------------------------------------------
1679     Bitmask<MAXNROFATTRIBUTESINWORDS> attributeMask;
1680     attributeMask = trigPtr->attributeMask;
1681     attributeMask.bitAND(req_struct->changeMask);
1682     numAttrsToRead = setAttrIds(attributeMask, regTabPtr->m_no_of_attributes,
1683 				&readBuffer[0]);
1684 
1685   } else if ((regOperPtr->op_struct.op_type == ZDELETE) &&
1686              (!trigPtr->sendBeforeValues)) {
1687     jam();
1688 //--------------------------------------------------------------------
1689 // Delete without sending before values only read Primary Key
1690 //--------------------------------------------------------------------
1691     return true;
1692   } else if (regOperPtr->op_struct.op_type != ZREFRESH){
1693     jam();
1694 //--------------------------------------------------------------------
1695 // All others send all attributes that are monitored, except:
1696 // Omit unchanged blob inlines on update i.e.
1697 // attributeMask & ~ (blobAttributeMask & ~ changeMask)
1698 //--------------------------------------------------------------------
1699     Bitmask<MAXNROFATTRIBUTESINWORDS> attributeMask;
1700     attributeMask = trigPtr->attributeMask;
1701     if (regOperPtr->op_struct.op_type == ZUPDATE) {
1702       Bitmask<MAXNROFATTRIBUTESINWORDS> tmpMask = regTabPtr->blobAttributeMask;
1703       tmpMask.bitANDC(req_struct->changeMask);
1704       attributeMask.bitANDC(tmpMask);
1705     }
1706     numAttrsToRead = setAttrIds(attributeMask, regTabPtr->m_no_of_attributes,
1707                                 &readBuffer[0]);
1708   }
1709   else
1710   {
1711     jam();
1712     ndbassert(regOperPtr->op_struct.op_type == ZREFRESH);
1713     /* Refresh specific before/after value hacks */
1714     switch(regOperPtr->m_copy_tuple_location.m_file_no){
1715     case Operationrec::RF_SINGLE_NOT_EXIST:
1716     case Operationrec::RF_MULTI_NOT_EXIST:
1717       return true; // generate ZDELETE...no before values
1718     case Operationrec::RF_SINGLE_EXIST:
1719     case Operationrec::RF_MULTI_EXIST:
1720       // generate ZINSERT...all after values
1721       numAttrsToRead = setAttrIds(trigPtr->attributeMask,
1722                                   regTabPtr->m_no_of_attributes,
1723                                   &readBuffer[0]);
1724       break;
1725     default:
1726       ndbrequire(false);
1727     }
1728   }
1729 
1730   ndbrequire(numAttrsToRead <= MAX_ATTRIBUTES_IN_TABLE);
1731 //--------------------------------------------------------------------
1732 // Read Main tuple values
1733 //--------------------------------------------------------------------
1734   if (regOperPtr->op_struct.op_type != ZDELETE)
1735   {
1736     jam();
1737     int ret = readAttributes(req_struct,
1738 			     &readBuffer[0],
1739 			     numAttrsToRead,
1740 			     afterBuffer,
1741 			     ZATTR_BUFFER_SIZE,
1742 			     false);
1743     ndbrequire(ret >= 0);
1744     noAfterWords= ret;
1745   } else {
1746     jam();
1747     noAfterWords = 0;
1748   }
1749 
1750 //--------------------------------------------------------------------
1751 // Read Copy tuple values for UPDATE's
1752 //--------------------------------------------------------------------
1753 // Initialise pagep and tuple offset for read of copy tuple
1754 //--------------------------------------------------------------------
1755   if ((regOperPtr->op_struct.op_type == ZUPDATE ||
1756        regOperPtr->op_struct.op_type == ZDELETE) &&
1757       (trigPtr->sendBeforeValues)) {
1758     jam();
1759 
1760     Tuple_header *save= req_struct->m_tuple_ptr;
1761     PagePtr tmp;
1762     if(regOperPtr->is_first_operation())
1763     {
1764       Uint32 *ptr= get_ptr(&tmp, &regOperPtr->m_tuple_location, regTabPtr);
1765       req_struct->m_tuple_ptr= (Tuple_header*)ptr;
1766     }
1767     else
1768     {
1769       req_struct->m_tuple_ptr =
1770         get_copy_tuple(&req_struct->prevOpPtr.p->m_copy_tuple_location);
1771     }
1772 
1773     if (regTabPtr->need_expand(disk))
1774       prepare_read(req_struct, regTabPtr, disk);
1775 
1776     int ret = readAttributes(req_struct,
1777 			     &readBuffer[0],
1778 			     numAttrsToRead,
1779 			     beforeBuffer,
1780 			     ZATTR_BUFFER_SIZE,
1781 			     false);
1782     req_struct->m_tuple_ptr= save;
1783     ndbrequire(ret >= 0);
1784     noBeforeWords = ret;
1785     if (refToMain(trigPtr->m_receiverRef) != SUMA &&
1786         (noAfterWords == noBeforeWords) &&
1787         (memcmp(afterBuffer, beforeBuffer, noAfterWords << 2) == 0)) {
1788 //--------------------------------------------------------------------
1789 // Although a trigger was fired it was not necessary since the old
1790 // value and the new value was exactly the same
1791 //--------------------------------------------------------------------
1792       jam();
1793       //XXX does this work with collations?
1794       return false;
1795     }
1796   }
1797   return true;
1798 }
1799 
sendTrigAttrInfo(Signal * signal,Uint32 * data,Uint32 dataLen,bool executeDirect,BlockReference receiverReference)1800 void Dbtup::sendTrigAttrInfo(Signal* signal,
1801                              Uint32* data,
1802                              Uint32  dataLen,
1803                              bool    executeDirect,
1804                              BlockReference receiverReference)
1805 {
1806   TrigAttrInfo* const trigAttrInfo = (TrigAttrInfo *)signal->getDataPtrSend();
1807   Uint32 sigLen;
1808   Uint32 dataIndex = 0;
1809   do {
1810     sigLen = dataLen - dataIndex;
1811     if (sigLen > TrigAttrInfo::DataLength) {
1812       jam();
1813       sigLen = TrigAttrInfo::DataLength;
1814     }
1815     MEMCOPY_NO_WORDS(trigAttrInfo->getData(),
1816                      data + dataIndex,
1817                      sigLen);
1818     if (executeDirect) {
1819       jam();
1820       EXECUTE_DIRECT(refToMain(receiverReference),
1821                      GSN_TRIG_ATTRINFO,
1822                      signal,
1823 		     TrigAttrInfo::StaticLength + sigLen);
1824       jamEntry();
1825     } else {
1826       jam();
1827       sendSignal(receiverReference,
1828                  GSN_TRIG_ATTRINFO,
1829                  signal,
1830                  TrigAttrInfo::StaticLength + sigLen,
1831                  JBB);
1832     }
1833     dataIndex += sigLen;
1834   } while (dataLen != dataIndex);
1835 }
1836 
1837 /*
1838  * Ordered index triggers.
1839  *
1840  * Insert: add entry to index
1841  * Update: add entry to index, de|ay remove until commit
1842  * Delete: do nothing, delay remove until commit
1843  * Commit: remove entry delayed from update and delete
1844  * Abort : remove entry added by insert and update
1845  *
1846  * See Notes.txt for the details.
1847  */
1848 
1849 int
executeTuxInsertTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)1850 Dbtup::executeTuxInsertTriggers(Signal* signal,
1851                                 Operationrec* regOperPtr,
1852                                 Fragrecord* regFragPtr,
1853                                 Tablerec* regTabPtr)
1854 {
1855   TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
1856   // fill in constant part
1857   req->tableId = regFragPtr->fragTableId;
1858   req->fragId = regFragPtr->fragmentId;
1859   req->pageId = regOperPtr->m_tuple_location.m_page_no;
1860   req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
1861   req->tupVersion = regOperPtr->tupVersion;
1862   req->opInfo = TuxMaintReq::OpAdd;
1863   return addTuxEntries(signal, regOperPtr, regTabPtr);
1864 }
1865 
1866 int
executeTuxUpdateTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)1867 Dbtup::executeTuxUpdateTriggers(Signal* signal,
1868                                 Operationrec* regOperPtr,
1869                                 Fragrecord* regFragPtr,
1870                                 Tablerec* regTabPtr)
1871 {
1872   TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
1873   // fill in constant part
1874   req->tableId = regFragPtr->fragTableId;
1875   req->fragId = regFragPtr->fragmentId;
1876   req->pageId = regOperPtr->m_tuple_location.m_page_no;
1877   req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
1878   req->tupVersion = regOperPtr->tupVersion;
1879   req->opInfo = TuxMaintReq::OpAdd;
1880   return addTuxEntries(signal, regOperPtr, regTabPtr);
1881 }
1882 
1883 int
addTuxEntries(Signal * signal,Operationrec * regOperPtr,Tablerec * regTabPtr)1884 Dbtup::addTuxEntries(Signal* signal,
1885                      Operationrec* regOperPtr,
1886                      Tablerec* regTabPtr)
1887 {
1888   if (ERROR_INSERTED(4022)) {
1889     jam();
1890     CLEAR_ERROR_INSERT_VALUE;
1891     terrorCode = 9999;
1892     return -1;
1893   }
1894   TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
1895   const DLList<TupTriggerData>& triggerList = regTabPtr->tuxCustomTriggers;
1896   TriggerPtr triggerPtr;
1897   Uint32 failPtrI;
1898   triggerList.first(triggerPtr);
1899   while (triggerPtr.i != RNIL) {
1900     jam();
1901     req->indexId = triggerPtr.p->indexId;
1902     req->errorCode = RNIL;
1903     if (ERROR_INSERTED(4023) &&
1904         ! triggerList.hasNext(triggerPtr)) {
1905       jam();
1906       CLEAR_ERROR_INSERT_VALUE;
1907       terrorCode = 9999;
1908       failPtrI = triggerPtr.i;
1909       goto fail;
1910     }
1911     EXECUTE_DIRECT(DBTUX, GSN_TUX_MAINT_REQ,
1912         signal, TuxMaintReq::SignalLength);
1913     jamEntry();
1914     if (req->errorCode != 0) {
1915       jam();
1916       terrorCode = req->errorCode;
1917       failPtrI = triggerPtr.i;
1918       goto fail;
1919     }
1920     triggerList.next(triggerPtr);
1921   }
1922   return 0;
1923 fail:
1924   req->opInfo = TuxMaintReq::OpRemove;
1925   triggerList.first(triggerPtr);
1926   while (triggerPtr.i != failPtrI) {
1927     jam();
1928     req->indexId = triggerPtr.p->indexId;
1929     req->errorCode = RNIL;
1930     EXECUTE_DIRECT(DBTUX, GSN_TUX_MAINT_REQ,
1931         signal, TuxMaintReq::SignalLength);
1932     jamEntry();
1933     ndbrequire(req->errorCode == 0);
1934     triggerList.next(triggerPtr);
1935   }
1936 #ifdef VM_TRACE
1937   ndbout << "aborted partial tux update: op " << hex << regOperPtr << endl;
1938 #endif
1939   return -1;
1940 }
1941 
1942 int
executeTuxDeleteTriggers(Signal * signal,Operationrec * const regOperPtr,Fragrecord * const regFragPtr,Tablerec * const regTabPtr)1943 Dbtup::executeTuxDeleteTriggers(Signal* signal,
1944                                 Operationrec* const regOperPtr,
1945                                 Fragrecord* const regFragPtr,
1946                                 Tablerec* const regTabPtr)
1947 {
1948   // do nothing
1949   return 0;
1950 }
1951 
1952 void
executeTuxCommitTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)1953 Dbtup::executeTuxCommitTriggers(Signal* signal,
1954                                 Operationrec* regOperPtr,
1955                                 Fragrecord* regFragPtr,
1956                                 Tablerec* regTabPtr)
1957 {
1958   TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
1959   Uint32 tupVersion;
1960   if (regOperPtr->op_struct.op_type == ZINSERT) {
1961     if (! regOperPtr->op_struct.delete_insert_flag)
1962       return;
1963     jam();
1964     tupVersion= decr_tup_version(regOperPtr->tupVersion);
1965   } else if (regOperPtr->op_struct.op_type == ZUPDATE) {
1966     jam();
1967     tupVersion= decr_tup_version(regOperPtr->tupVersion);
1968   } else if (regOperPtr->op_struct.op_type == ZDELETE) {
1969     if (regOperPtr->op_struct.delete_insert_flag)
1970       return;
1971     jam();
1972     tupVersion= regOperPtr->tupVersion;
1973   } else if (regOperPtr->op_struct.op_type == ZREFRESH) {
1974     /* Refresh should not affect TUX */
1975     return;
1976   } else {
1977     ndbrequire(false);
1978     tupVersion= 0; // remove warning
1979   }
1980   // fill in constant part
1981   req->tableId = regFragPtr->fragTableId;
1982   req->fragId = regFragPtr->fragmentId;
1983   req->pageId = regOperPtr->m_tuple_location.m_page_no;
1984   req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
1985   req->tupVersion = tupVersion;
1986   req->opInfo = TuxMaintReq::OpRemove;
1987   removeTuxEntries(signal, regTabPtr);
1988 }
1989 
1990 void
executeTuxAbortTriggers(Signal * signal,Operationrec * regOperPtr,Fragrecord * regFragPtr,Tablerec * regTabPtr)1991 Dbtup::executeTuxAbortTriggers(Signal* signal,
1992                                Operationrec* regOperPtr,
1993                                Fragrecord* regFragPtr,
1994                                Tablerec* regTabPtr)
1995 {
1996   TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
1997   // get version
1998   Uint32 tupVersion;
1999   if (regOperPtr->op_struct.op_type == ZINSERT) {
2000     jam();
2001     tupVersion = regOperPtr->tupVersion;
2002   } else if (regOperPtr->op_struct.op_type == ZUPDATE) {
2003     jam();
2004     tupVersion = regOperPtr->tupVersion;
2005   } else if (regOperPtr->op_struct.op_type == ZDELETE) {
2006     jam();
2007     return;
2008   } else if (regOperPtr->op_struct.op_type == ZREFRESH) {
2009     jam();
2010     /* Refresh should not affect TUX */
2011     return;
2012   } else {
2013     ndbrequire(false);
2014     tupVersion= 0; // remove warning
2015   }
2016   // fill in constant part
2017   req->tableId = regFragPtr->fragTableId;
2018   req->fragId = regFragPtr->fragmentId;
2019   req->pageId = regOperPtr->m_tuple_location.m_page_no;
2020   req->pageIndex = regOperPtr->m_tuple_location.m_page_idx;
2021   req->tupVersion = tupVersion;
2022   req->opInfo = TuxMaintReq::OpRemove;
2023   removeTuxEntries(signal, regTabPtr);
2024 }
2025 
2026 void
removeTuxEntries(Signal * signal,Tablerec * regTabPtr)2027 Dbtup::removeTuxEntries(Signal* signal,
2028                         Tablerec* regTabPtr)
2029 {
2030   TuxMaintReq* const req = (TuxMaintReq*)signal->getDataPtrSend();
2031   const DLList<TupTriggerData>& triggerList = regTabPtr->tuxCustomTriggers;
2032   TriggerPtr triggerPtr;
2033   triggerList.first(triggerPtr);
2034   while (triggerPtr.i != RNIL) {
2035     jam();
2036     req->indexId = triggerPtr.p->indexId;
2037     req->errorCode = RNIL,
2038     EXECUTE_DIRECT(DBTUX, GSN_TUX_MAINT_REQ,
2039         signal, TuxMaintReq::SignalLength);
2040     jamEntry();
2041     // must succeed
2042     ndbrequire(req->errorCode == 0);
2043     triggerList.next(triggerPtr);
2044   }
2045 }
2046 
2047 void
ndbmtd_buffer_suma_trigger(Signal * signal,Uint32 len,LinearSectionPtr sec[3])2048 Dbtup::ndbmtd_buffer_suma_trigger(Signal * signal,
2049                                   Uint32 len,
2050                                   LinearSectionPtr sec[3])
2051 {
2052   jam();
2053   Uint32 tot = len + 5;
2054   for (Uint32 i = 0; i<3; i++)
2055     tot += sec[i].sz;
2056 
2057   Uint32 * ptr = 0;
2058   Uint32 free = m_suma_trigger_buffer.m_freeWords;
2059   Uint32 pageId = m_suma_trigger_buffer.m_pageId;
2060   Uint32 oom = m_suma_trigger_buffer.m_out_of_memory;
2061   if (free < tot)
2062   {
2063     jam();
2064     if (pageId != RNIL)
2065     {
2066       flush_ndbmtd_suma_buffer(signal);
2067     }
2068     if (oom == 0)
2069     {
2070       jam();
2071       ndbassert(m_suma_trigger_buffer.m_pageId == RNIL);
2072       void * vptr = m_ctx.m_mm.alloc_page(RT_DBTUP_PAGE,
2073                                           &m_suma_trigger_buffer.m_pageId,
2074                                           Ndbd_mem_manager::NDB_ZONE_ANY);
2075       ptr = reinterpret_cast<Uint32*>(vptr);
2076       free = GLOBAL_PAGE_SIZE_WORDS - tot;
2077     }
2078   }
2079   else
2080   {
2081     jam();
2082     ptr = reinterpret_cast<Uint32*>(c_page_pool.getPtr(pageId));
2083     ptr += (GLOBAL_PAGE_SIZE_WORDS - free);
2084     free -= tot;
2085   }
2086 
2087   if (likely(ptr != 0))
2088   {
2089     jam();
2090     * ptr++ = tot;
2091     * ptr++ = len;
2092     * ptr++ = sec[0].sz;
2093     * ptr++ = sec[1].sz;
2094     * ptr++ = sec[2].sz;
2095     memcpy(ptr, signal->getDataPtrSend(), 4 * len);
2096     ptr += len;
2097     for (Uint32 i = 0; i<3; i++)
2098     {
2099       memcpy(ptr, sec[i].p, 4 * sec[i].sz);
2100       ptr += sec[i].sz;
2101     }
2102 
2103     m_suma_trigger_buffer.m_freeWords = free;
2104     if (free < (len + 5))
2105     {
2106       flush_ndbmtd_suma_buffer(signal);
2107     }
2108   }
2109   else
2110   {
2111     jam();
2112     m_suma_trigger_buffer.m_out_of_memory = 1;
2113   }
2114 }
2115 
2116 void
flush_ndbmtd_suma_buffer(Signal * signal)2117 Dbtup::flush_ndbmtd_suma_buffer(Signal* signal)
2118 {
2119   jam();
2120 
2121   Uint32 pageId = m_suma_trigger_buffer.m_pageId;
2122   Uint32 free = m_suma_trigger_buffer.m_freeWords;
2123   Uint32 oom = m_suma_trigger_buffer.m_out_of_memory;
2124 
2125   if (pageId != RNIL)
2126   {
2127     jam();
2128     Uint32 save[2];
2129     save[0] = signal->theData[0];
2130     save[1] = signal->theData[1];
2131     signal->theData[0] = pageId;
2132     signal->theData[1] =  GLOBAL_PAGE_SIZE_WORDS - free;
2133     sendSignal(SUMA_REF, GSN_FIRE_TRIG_ORD_L, signal, 2, JBB);
2134 
2135     signal->theData[0] = save[0];
2136     signal->theData[1] = save[1];
2137   }
2138   else if (oom)
2139   {
2140     jam();
2141     Uint32 save[2];
2142     save[0] = signal->theData[0];
2143     save[1] = signal->theData[1];
2144     signal->theData[0] = RNIL;
2145     signal->theData[1] =  0;
2146     sendSignal(SUMA_REF, GSN_FIRE_TRIG_ORD_L, signal, 2, JBB);
2147 
2148     signal->theData[0] = save[0];
2149     signal->theData[1] = save[1];
2150   }
2151 
2152   m_suma_trigger_buffer.m_pageId = RNIL;
2153   m_suma_trigger_buffer.m_freeWords = 0;
2154   m_suma_trigger_buffer.m_out_of_memory = 0;
2155 }
2156 
2157 void
execSUB_GCP_COMPLETE_REP(Signal * signal)2158 Dbtup::execSUB_GCP_COMPLETE_REP(Signal* signal)
2159 {
2160   flush_ndbmtd_suma_buffer(signal);
2161 }
2162