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