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