MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ha_ndbcluster.cc
Go to the documentation of this file.
1 /* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
24 #include "ha_ndbcluster_glue.h"
25 
26 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
27 #include "ha_ndbcluster.h"
28 #include <ndbapi/NdbApi.hpp>
29 #include <util/Bitmask.hpp>
30 #include <ndbapi/NdbIndexStat.hpp>
31 #include <ndbapi/NdbInterpretedCode.hpp>
32 #include "../storage/ndb/src/ndbapi/NdbQueryBuilder.hpp"
33 #include "../storage/ndb/src/ndbapi/NdbQueryOperation.hpp"
34 
35 #include "ha_ndbcluster_binlog.h"
36 #include "ha_ndbcluster_push.h"
37 #include "ha_ndbcluster_cond.h"
38 #include "ha_ndbcluster_tables.h"
39 #include "ha_ndbcluster_connection.h"
40 #include "ndb_thd.h"
41 #include "ndb_table_guard.h"
42 #include "ndb_global_schema_lock.h"
43 #include "ndb_global_schema_lock_guard.h"
44 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
45 #include "abstract_query_plan.h"
46 #endif
47 #include "ndb_dist_priv_util.h"
48 #include "ha_ndb_index_stat.h"
49 
50 #include <mysql/plugin.h>
51 #include <ndb_version.h>
52 #include "ndb_mi.h"
53 
54 // ndb interface initialization/cleanup
55 extern "C" void ndb_init_internal();
56 extern "C" void ndb_end_internal();
57 
58 static const int DEFAULT_PARALLELISM= 0;
59 static const ha_rows DEFAULT_AUTO_PREFETCH= 32;
60 static const ulong ONE_YEAR_IN_SECONDS= (ulong) 3600L*24L*365L;
61 
62 ulong opt_ndb_extra_logging;
63 static ulong opt_ndb_wait_connected;
64 ulong opt_ndb_wait_setup;
65 static ulong opt_ndb_cache_check_time;
66 static uint opt_ndb_cluster_connection_pool;
67 static char* opt_ndb_index_stat_option;
68 static char* opt_ndb_connectstring;
69 static uint opt_ndb_nodeid;
70 
71 static MYSQL_THDVAR_UINT(
72  autoincrement_prefetch_sz, /* name */
73  PLUGIN_VAR_RQCMDARG,
74  "Specify number of autoincrement values that are prefetched.",
75  NULL, /* check func. */
76  NULL, /* update func. */
77  1, /* default */
78  1, /* min */
79  65535, /* max */
80  0 /* block */
81 );
82 
83 
84 static MYSQL_THDVAR_BOOL(
85  force_send, /* name */
86  PLUGIN_VAR_OPCMDARG,
87  "Force send of buffers to ndb immediately without waiting for "
88  "other threads.",
89  NULL, /* check func. */
90  NULL, /* update func. */
91  1 /* default */
92 );
93 
94 
95 static MYSQL_THDVAR_BOOL(
96  use_exact_count, /* name */
97  PLUGIN_VAR_OPCMDARG,
98  "Use exact records count during query planning and for fast "
99  "select count(*), disable for faster queries.",
100  NULL, /* check func. */
101  NULL, /* update func. */
102  0 /* default */
103 );
104 
105 
106 static MYSQL_THDVAR_BOOL(
107  use_transactions, /* name */
108  PLUGIN_VAR_OPCMDARG,
109  "Use transactions for large inserts, if enabled then large "
110  "inserts will be split into several smaller transactions",
111  NULL, /* check func. */
112  NULL, /* update func. */
113  1 /* default */
114 );
115 
116 
117 static MYSQL_THDVAR_BOOL(
118  use_copying_alter_table, /* name */
119  PLUGIN_VAR_OPCMDARG,
120  "Force ndbcluster to always copy tables at alter table (should "
121  "only be used if on-line alter table fails).",
122  NULL, /* check func. */
123  NULL, /* update func. */
124  0 /* default */
125 );
126 
127 
128 static MYSQL_THDVAR_UINT(
129  optimized_node_selection, /* name */
130  PLUGIN_VAR_OPCMDARG,
131  "Select nodes for transactions in a more optimal way.",
132  NULL, /* check func. */
133  NULL, /* update func. */
134  3, /* default */
135  0, /* min */
136  3, /* max */
137  0 /* block */
138 );
139 
140 
141 static MYSQL_THDVAR_ULONG(
142  batch_size, /* name */
143  PLUGIN_VAR_RQCMDARG,
144  "Batch size in bytes.",
145  NULL, /* check func. */
146  NULL, /* update func. */
147  32768, /* default */
148  0, /* min */
149  ONE_YEAR_IN_SECONDS, /* max */
150  0 /* block */
151 );
152 
153 
154 static MYSQL_THDVAR_ULONG(
155  optimization_delay, /* name */
156  PLUGIN_VAR_RQCMDARG,
157  "For optimize table, specifies the delay in milliseconds "
158  "for each batch of rows sent.",
159  NULL, /* check func. */
160  NULL, /* update func. */
161  10, /* default */
162  0, /* min */
163  100000, /* max */
164  0 /* block */
165 );
166 
167 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
168 #define DEFAULT_NDB_INDEX_STAT_ENABLE FALSE
169 #else
170 #define DEFAULT_NDB_INDEX_STAT_ENABLE TRUE
171 #endif
172 
173 static MYSQL_THDVAR_BOOL(
174  index_stat_enable, /* name */
175  PLUGIN_VAR_OPCMDARG,
176  "Use ndb index statistics in query optimization.",
177  NULL, /* check func. */
178  NULL, /* update func. */
179  DEFAULT_NDB_INDEX_STAT_ENABLE /* default */
180 );
181 
182 
183 static MYSQL_THDVAR_ULONG(
184  index_stat_cache_entries, /* name */
185  PLUGIN_VAR_NOCMDARG,
186  "Obsolete (ignored and will be removed later).",
187  NULL, /* check func. */
188  NULL, /* update func. */
189  32, /* default */
190  0, /* min */
191  ULONG_MAX, /* max */
192  0 /* block */
193 );
194 
195 
196 static MYSQL_THDVAR_ULONG(
197  index_stat_update_freq, /* name */
198  PLUGIN_VAR_NOCMDARG,
199  "Obsolete (ignored and will be removed later).",
200  NULL, /* check func. */
201  NULL, /* update func. */
202  20, /* default */
203  0, /* min */
204  ULONG_MAX, /* max */
205  0 /* block */
206 );
207 
208 
209 static MYSQL_THDVAR_BOOL(
210  table_no_logging, /* name */
211  PLUGIN_VAR_NOCMDARG,
212  "",
213  NULL, /* check func. */
214  NULL, /* update func. */
215  FALSE /* default */
216 );
217 
218 
219 static MYSQL_THDVAR_BOOL(
220  table_temporary, /* name */
221  PLUGIN_VAR_NOCMDARG,
222  "",
223  NULL, /* check func. */
224  NULL, /* update func. */
225  FALSE /* default */
226 );
227 
228 static MYSQL_THDVAR_UINT(
229  blob_read_batch_bytes, /* name */
230  PLUGIN_VAR_RQCMDARG,
231  "Specifies the bytesize large Blob reads "
232  "should be batched into. 0 == No limit.",
233  NULL, /* check func */
234  NULL, /* update func */
235  65536, /* default */
236  0, /* min */
237  UINT_MAX, /* max */
238  0 /* block */
239 );
240 
241 static MYSQL_THDVAR_UINT(
242  blob_write_batch_bytes, /* name */
243  PLUGIN_VAR_RQCMDARG,
244  "Specifies the bytesize large Blob writes "
245  "should be batched into. 0 == No limit.",
246  NULL, /* check func */
247  NULL, /* update func */
248  65536, /* default */
249  0, /* min */
250  UINT_MAX, /* max */
251  0 /* block */
252 );
253 
254 static MYSQL_THDVAR_UINT(
255  deferred_constraints, /* name */
256  PLUGIN_VAR_RQCMDARG,
257  "Specified that constraints should be checked deferred (when supported)",
258  NULL, /* check func */
259  NULL, /* update func */
260  0, /* default */
261  0, /* min */
262  1, /* max */
263  0 /* block */
264 );
265 
266 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
267 #define DEFAULT_NDB_JOIN_PUSHDOWN FALSE
268 #else
269 #define DEFAULT_NDB_JOIN_PUSHDOWN TRUE
270 #endif
271 
272 static MYSQL_THDVAR_BOOL(
273  join_pushdown, /* name */
274  PLUGIN_VAR_OPCMDARG,
275  "Enable pushing down of join to datanodes",
276  NULL, /* check func. */
277  NULL, /* update func. */
278  DEFAULT_NDB_JOIN_PUSHDOWN /* default */
279 );
280 
281 /*
282  Required in index_stat.cc but available only from here
283  thanks to use of top level anonymous structs.
284 */
285 bool ndb_index_stat_get_enable(THD *thd)
286 {
287  const bool value = THDVAR(thd, index_stat_enable);
288  return value;
289 }
290 
291 static int ndbcluster_end(handlerton *hton, ha_panic_function flag);
292 static bool ndbcluster_show_status(handlerton *hton, THD*,
293  stat_print_fn *,
294  enum ha_stat_type);
295 static int ndbcluster_alter_tablespace(handlerton *hton,
296  THD* thd,
297  st_alter_tablespace *info);
298 static int ndbcluster_fill_files_table(handlerton *hton,
299  THD *thd,
300  TABLE_LIST *tables,
301  Item *cond);
302 
303 #if MYSQL_VERSION_ID >= 50501
304 
315 static int
316 ndbcluster_fill_is_table(handlerton *hton, THD *thd, TABLE_LIST *tables,
317  Item *cond, enum enum_schema_tables schema_table_idx)
318 {
319  if (schema_table_idx == SCH_FILES)
320  return ndbcluster_fill_files_table(hton, thd, tables, cond);
321  return 0;
322 }
323 #endif
324 
325 
326 handlerton *ndbcluster_hton;
327 
328 static handler *ndbcluster_create_handler(handlerton *hton,
330  MEM_ROOT *mem_root)
331 {
332  return new (mem_root) ha_ndbcluster(hton, table);
333 }
334 
335 static uint
336 ndbcluster_partition_flags()
337 {
338  return (HA_CAN_PARTITION | HA_CAN_UPDATE_PARTITION_KEY |
339  HA_CAN_PARTITION_UNIQUE | HA_USE_AUTO_PARTITION);
340 }
341 
342 #ifndef NDB_WITHOUT_ONLINE_ALTER
343 static uint
344 ndbcluster_alter_table_flags(uint flags)
345 {
346  if (flags & ALTER_DROP_PARTITION)
347  return 0;
348  else
349  return (HA_PARTITION_FUNCTION_SUPPORTED);
350 }
351 #else
352 static uint
353 ndbcluster_alter_table_flags(uint flags)
354 {
355  const uint f=
356  HA_PARTITION_FUNCTION_SUPPORTED |
357  0;
358 
359  if (flags & Alter_info::ALTER_DROP_PARTITION)
360  return 0;
361 
362  return f;
363 }
364 #endif
365 
366 #define NDB_AUTO_INCREMENT_RETRIES 100
367 #define BATCH_FLUSH_SIZE (32768)
368 /*
369  Room for 10 instruction words, two labels (@ 2words/label)
370  + 2 extra words for the case of resolve_size == 8
371 */
372 #define MAX_CONFLICT_INTERPRETED_PROG_SIZE 16
373 
374 static int ndb_to_mysql_error(const NdbError *ndberr);
375 
376 #define ERR_PRINT(err) \
377  DBUG_PRINT("error", ("%d message: %s", err.code, err.message))
378 
379 #define ERR_RETURN(err) \
380 { \
381  const NdbError& tmp= err; \
382  DBUG_RETURN(ndb_to_mysql_error(&tmp)); \
383 }
384 
385 #define ERR_BREAK(err, code) \
386 { \
387  const NdbError& tmp= err; \
388  code= ndb_to_mysql_error(&tmp); \
389  break; \
390 }
391 
392 #define ERR_SET(err, code) \
393 { \
394  const NdbError& tmp= err; \
395  code= ndb_to_mysql_error(&tmp); \
396 }
397 
398 static int ndbcluster_inited= 0;
399 int ndbcluster_terminating= 0;
400 
401 /*
402  Indicator and CONDVAR used to delay client and slave
403  connections until Ndb has Binlog setup
404  (bug#46955)
405 */
406 int ndb_setup_complete= 0;
407 pthread_cond_t COND_ndb_setup_complete; // Signal with ndbcluster_mutex
408 
409 extern Ndb* g_ndb;
410 
411 uchar g_node_id_map[max_ndb_nodes];
412 
414 pthread_mutex_t ndbcluster_mutex;
415 
417 HASH ndbcluster_open_tables;
418 
419 static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
420  my_bool not_used __attribute__((unused)));
421 
422 static void modify_shared_stats(NDB_SHARE *share,
423  Ndb_local_table_statistics *local_stat);
424 
425 static int ndb_get_table_statistics(THD *thd, ha_ndbcluster*, bool, Ndb*,
426  const NdbRecord *, struct Ndb_statistics *,
427  bool have_lock= FALSE,
428  uint part_id= ~(uint)0);
429 
430 THD *injector_thd= 0;
431 
432 // Util thread variables
433 pthread_t ndb_util_thread;
434 int ndb_util_thread_running= 0;
435 pthread_mutex_t LOCK_ndb_util_thread;
436 pthread_cond_t COND_ndb_util_thread;
437 pthread_cond_t COND_ndb_util_ready;
438 pthread_handler_t ndb_util_thread_func(void *arg);
439 
440 // Index stats thread variables
441 pthread_t ndb_index_stat_thread;
442 int ndb_index_stat_thread_running= 0;
443 pthread_mutex_t LOCK_ndb_index_stat_thread;
444 pthread_cond_t COND_ndb_index_stat_thread;
445 pthread_cond_t COND_ndb_index_stat_ready;
446 pthread_mutex_t ndb_index_stat_list_mutex;
447 pthread_mutex_t ndb_index_stat_stat_mutex;
448 pthread_cond_t ndb_index_stat_stat_cond;
449 pthread_handler_t ndb_index_stat_thread_func(void *arg);
450 
451 extern void ndb_index_stat_free(NDB_SHARE *share);
452 extern void ndb_index_stat_end();
453 
454 /* Status variables shown with 'show status like 'Ndb%' */
455 
456 struct st_ndb_status g_ndb_status;
457 
458 long g_ndb_status_index_stat_cache_query = 0;
459 long g_ndb_status_index_stat_cache_clean = 0;
460 
461 long long g_event_data_count = 0;
462 long long g_event_nondata_count = 0;
463 long long g_event_bytes_count = 0;
464 
465 static long long g_slave_api_client_stats[Ndb::NumClientStatistics];
466 
467 static long long g_server_api_client_stats[Ndb::NumClientStatistics];
468 
469 void
470 update_slave_api_stats(Ndb* ndb)
471 {
472  for (Uint32 i=0; i < Ndb::NumClientStatistics; i++)
473  g_slave_api_client_stats[i] = ndb->getClientStat(i);
474 }
475 
476 st_ndb_slave_state g_ndb_slave_state;
477 
478 st_ndb_slave_state::st_ndb_slave_state()
479  : current_conflict_defined_op_count(0),
480  current_master_server_epoch(0),
481  current_max_rep_epoch(0),
482  max_rep_epoch(0),
483  sql_run_id(~Uint32(0))
484 {
485  memset(current_violation_count, 0, sizeof(current_violation_count));
486  memset(total_violation_count, 0, sizeof(total_violation_count));
487 };
488 
489 void
490 st_ndb_slave_state::atTransactionAbort()
491 {
492  /* Reset current-transaction counters + state */
493  memset(current_violation_count, 0, sizeof(current_violation_count));
494  current_conflict_defined_op_count = 0;
495  current_max_rep_epoch = 0;
496 }
497 
498 void
499 st_ndb_slave_state::atTransactionCommit()
500 {
501  /* Merge committed transaction counters into total state
502  * Then reset current transaction counters
503  */
504  for (int i=0; i < CFT_NUMBER_OF_CFTS; i++)
505  {
506  total_violation_count[i]+= current_violation_count[i];
507  current_violation_count[i] = 0;
508  }
509  current_conflict_defined_op_count = 0;
510  if (current_max_rep_epoch > max_rep_epoch)
511  {
512  DBUG_PRINT("info", ("Max replicated epoch increases from %llu to %llu",
513  max_rep_epoch,
514  current_max_rep_epoch));
515 
516  max_rep_epoch = current_max_rep_epoch;
517  }
518  current_max_rep_epoch = 0;
519 }
520 
521 void
522 st_ndb_slave_state::atApplyStatusWrite(Uint32 master_server_id,
523  Uint32 row_server_id,
524  Uint64 row_epoch,
525  bool is_row_server_id_local)
526 {
527  if (row_server_id == master_server_id)
528  {
529  /*
530  WRITE_ROW to ndb_apply_status injected by MySQLD
531  immediately upstream of us.
532  Record epoch
533  */
534  current_master_server_epoch = row_epoch;
535  assert(! is_row_server_id_local);
536  }
537  else if (is_row_server_id_local)
538  {
539  DBUG_PRINT("info", ("Recording application of local server %u epoch %llu "
540  " which is %s.",
541  row_server_id, row_epoch,
542  (row_epoch > g_ndb_slave_state.current_max_rep_epoch)?
543  " new highest." : " older than previously applied"));
544  if (row_epoch > current_max_rep_epoch)
545  {
546  /*
547  Store new highest epoch in thdvar. If we commit successfully
548  then this can become the new global max
549  */
550  current_max_rep_epoch = row_epoch;
551  }
552  }
553 }
554 
555 void
556 st_ndb_slave_state::atResetSlave()
557 {
558  /* Reset the Maximum replicated epoch vars
559  * on slave reset
560  * No need to touch the sql_run_id as that
561  * will increment if the slave is started
562  * again.
563  */
564  current_max_rep_epoch = 0;
565  max_rep_epoch = 0;
566 }
567 
568 static int check_slave_state(THD* thd)
569 {
570  DBUG_ENTER("check_slave_state");
571 
572 #ifdef HAVE_NDB_BINLOG
573  if (!thd->slave_thread)
574  DBUG_RETURN(0);
575 
576  const Uint32 runId = ndb_mi_get_slave_run_id();
577  DBUG_PRINT("info", ("Slave SQL thread run id is %u",
578  runId));
579  if (unlikely(runId != g_ndb_slave_state.sql_run_id))
580  {
581  DBUG_PRINT("info", ("Slave run id changed from %u, "
582  "treating as Slave restart",
583  g_ndb_slave_state.sql_run_id));
584  g_ndb_slave_state.sql_run_id = runId;
585 
586  /* Always try to load the Max Replicated Epoch info
587  * first.
588  * Could be made optional if it's a problem
589  */
590  {
591  /*
592  Load highest replicated epoch from a local
593  MySQLD from the cluster.
594  */
595  DBUG_PRINT("info", ("Loading applied epoch information from %s",
596  NDB_APPLY_TABLE));
597  NdbError ndb_error;
598  Uint64 highestAppliedEpoch = 0;
599  do
600  {
601  Ndb* ndb= check_ndb_in_thd(thd);
602  NDBDICT* dict= ndb->getDictionary();
603  NdbTransaction* trans= NULL;
604  ndb->setDatabaseName(NDB_REP_DB);
605  Ndb_table_guard ndbtab_g(dict, NDB_APPLY_TABLE);
606 
607  const NDBTAB* ndbtab= ndbtab_g.get_table();
608  if (unlikely(ndbtab == NULL))
609  {
610  ndb_error = dict->getNdbError();
611  break;
612  }
613 
614  trans= ndb->startTransaction();
615  if (unlikely(trans == NULL))
616  {
617  ndb_error = ndb->getNdbError();
618  break;
619  }
620 
621  do
622  {
623  NdbScanOperation* sop = trans->getNdbScanOperation(ndbtab);
624  if (unlikely(sop == NULL))
625  {
626  ndb_error = trans->getNdbError();
627  break;
628  }
629 
630  const Uint32 server_id_col_num = 0;
631  const Uint32 epoch_col_num = 1;
632  NdbRecAttr* server_id_ra = 0;
633  NdbRecAttr* epoch_ra = 0;
634 
635  if (unlikely((sop->readTuples(NdbOperation::LM_CommittedRead) != 0) ||
636  ((server_id_ra = sop->getValue(server_id_col_num)) == NULL) ||
637  ((epoch_ra = sop->getValue(epoch_col_num)) == NULL)))
638  {
639  ndb_error = sop->getNdbError();
640  break;
641  }
642 
643  if (trans->execute(NdbTransaction::Commit))
644  {
645  ndb_error = trans->getNdbError();
646  break;
647  }
648 
649  int rc = 0;
650  while (0 == (rc= sop->nextResult(true)))
651  {
652  Uint32 serverid = server_id_ra->u_32_value();
653  Uint64 epoch = epoch_ra->u_64_value();
654 
655  if ((serverid == ::server_id) ||
656  (ndb_mi_get_ignore_server_id(serverid)))
657  {
658  highestAppliedEpoch = MAX(epoch, highestAppliedEpoch);
659  }
660  }
661 
662  if (rc != 1)
663  {
664  ndb_error = sop->getNdbError();
665  break;
666  }
667  } while (0);
668 
669  trans->close();
670  } while(0);
671 
672  if (ndb_error.code != 0)
673  {
674  sql_print_warning("NDB Slave : Could not determine maximum replicated epoch from %s.%s "
675  "at Slave start, error %u %s",
676  NDB_REP_DB,
677  NDB_APPLY_TABLE,
678  ndb_error.code, ndb_error.message);
679  }
680 
681  /*
682  Set Global status variable to the Highest Applied Epoch from
683  the Cluster DB.
684  If none was found, this will be zero.
685  */
686  g_ndb_slave_state.max_rep_epoch = highestAppliedEpoch;
687  sql_print_information("NDB Slave : MaxReplicatedEpoch set to %llu (%u/%u) at Slave start",
688  g_ndb_slave_state.max_rep_epoch,
689  (Uint32)(g_ndb_slave_state.max_rep_epoch >> 32),
690  (Uint32)(g_ndb_slave_state.max_rep_epoch & 0xffffffff));
691  } // Load highest replicated epoch
692  } // New Slave SQL thread run id
693 #endif
694 
695  DBUG_RETURN(0);
696 }
697 
698 
699 static int update_status_variables(Thd_ndb *thd_ndb,
700  st_ndb_status *ns,
702 {
703  ns->connected_port= c->get_connected_port();
704  ns->connected_host= c->get_connected_host();
705  if (ns->cluster_node_id != (int) c->node_id())
706  {
707  ns->cluster_node_id= c->node_id();
708  if (&g_ndb_status == ns && g_ndb_cluster_connection == c)
709  sql_print_information("NDB: NodeID is %lu, management server '%s:%lu'",
710  ns->cluster_node_id, ns->connected_host,
711  ns->connected_port);
712  }
713  ns->number_of_replicas= 0;
714  {
715  int n= c->get_no_ready();
716  ns->number_of_ready_data_nodes= n > 0 ? n : 0;
717  }
718  ns->number_of_data_nodes= c->no_db_nodes();
719  ns->connect_count= c->get_connect_count();
720  if (thd_ndb)
721  {
722  ns->execute_count= thd_ndb->m_execute_count;
723  ns->scan_count= thd_ndb->m_scan_count;
724  ns->pruned_scan_count= thd_ndb->m_pruned_scan_count;
725  ns->sorted_scan_count= thd_ndb->m_sorted_scan_count;
726  ns->pushed_queries_defined= thd_ndb->m_pushed_queries_defined;
727  ns->pushed_queries_dropped= thd_ndb->m_pushed_queries_dropped;
728  ns->pushed_queries_executed= thd_ndb->m_pushed_queries_executed;
729  ns->pushed_reads= thd_ndb->m_pushed_reads;
730  for (int i= 0; i < MAX_NDB_NODES; i++)
731  {
732  ns->transaction_no_hint_count[i]= thd_ndb->m_transaction_no_hint_count[i];
733  ns->transaction_hint_count[i]= thd_ndb->m_transaction_hint_count[i];
734  }
735  for (int i=0; i < Ndb::NumClientStatistics; i++)
736  {
737  ns->api_client_stats[i] = thd_ndb->ndb->getClientStat(i);
738  }
739  ns->schema_locks_count= thd_ndb->schema_locks_count;
740  }
741  return 0;
742 }
743 
744 /* Helper macro for definitions of NdbApi status variables */
745 
746 #define NDBAPI_COUNTERS(NAME_SUFFIX, ARRAY_LOCATION) \
747  {"api_wait_exec_complete_count" NAME_SUFFIX, \
748  (char*) ARRAY_LOCATION[ Ndb::WaitExecCompleteCount ], \
749  SHOW_LONGLONG}, \
750  {"api_wait_scan_result_count" NAME_SUFFIX, \
751  (char*) ARRAY_LOCATION[ Ndb::WaitScanResultCount ], \
752  SHOW_LONGLONG}, \
753  {"api_wait_meta_request_count" NAME_SUFFIX, \
754  (char*) ARRAY_LOCATION[ Ndb::WaitMetaRequestCount ], \
755  SHOW_LONGLONG}, \
756  {"api_wait_nanos_count" NAME_SUFFIX, \
757  (char*) ARRAY_LOCATION[ Ndb::WaitNanosCount ], \
758  SHOW_LONGLONG}, \
759  {"api_bytes_sent_count" NAME_SUFFIX, \
760  (char*) ARRAY_LOCATION[ Ndb::BytesSentCount ], \
761  SHOW_LONGLONG}, \
762  {"api_bytes_received_count" NAME_SUFFIX, \
763  (char*) ARRAY_LOCATION[ Ndb::BytesRecvdCount ], \
764  SHOW_LONGLONG}, \
765  {"api_trans_start_count" NAME_SUFFIX, \
766  (char*) ARRAY_LOCATION[ Ndb::TransStartCount ], \
767  SHOW_LONGLONG}, \
768  {"api_trans_commit_count" NAME_SUFFIX, \
769  (char*) ARRAY_LOCATION[ Ndb::TransCommitCount ], \
770  SHOW_LONGLONG}, \
771  {"api_trans_abort_count" NAME_SUFFIX, \
772  (char*) ARRAY_LOCATION[ Ndb::TransAbortCount ], \
773  SHOW_LONGLONG}, \
774  {"api_trans_close_count" NAME_SUFFIX, \
775  (char*) ARRAY_LOCATION[ Ndb::TransCloseCount ], \
776  SHOW_LONGLONG}, \
777  {"api_pk_op_count" NAME_SUFFIX, \
778  (char*) ARRAY_LOCATION[ Ndb::PkOpCount ], \
779  SHOW_LONGLONG}, \
780  {"api_uk_op_count" NAME_SUFFIX, \
781  (char*) ARRAY_LOCATION[ Ndb::UkOpCount ], \
782  SHOW_LONGLONG}, \
783  {"api_table_scan_count" NAME_SUFFIX, \
784  (char*) ARRAY_LOCATION[ Ndb::TableScanCount ], \
785  SHOW_LONGLONG}, \
786  {"api_range_scan_count" NAME_SUFFIX, \
787  (char*) ARRAY_LOCATION[ Ndb::RangeScanCount ], \
788  SHOW_LONGLONG}, \
789  {"api_pruned_scan_count" NAME_SUFFIX, \
790  (char*) ARRAY_LOCATION[ Ndb::PrunedScanCount ], \
791  SHOW_LONGLONG}, \
792  {"api_scan_batch_count" NAME_SUFFIX, \
793  (char*) ARRAY_LOCATION[ Ndb::ScanBatchCount ], \
794  SHOW_LONGLONG}, \
795  {"api_read_row_count" NAME_SUFFIX, \
796  (char*) ARRAY_LOCATION[ Ndb::ReadRowCount ], \
797  SHOW_LONGLONG}, \
798  {"api_trans_local_read_row_count" NAME_SUFFIX, \
799  (char*) ARRAY_LOCATION[ Ndb::TransLocalReadRowCount ], \
800  SHOW_LONGLONG}
801 
802 SHOW_VAR ndb_status_variables_dynamic[]= {
803  {"cluster_node_id", (char*) &g_ndb_status.cluster_node_id, SHOW_LONG},
804  {"config_from_host", (char*) &g_ndb_status.connected_host, SHOW_CHAR_PTR},
805  {"config_from_port", (char*) &g_ndb_status.connected_port, SHOW_LONG},
806 //{"number_of_replicas", (char*) &g_ndb_status.number_of_replicas, SHOW_LONG},
807  {"number_of_data_nodes",(char*) &g_ndb_status.number_of_data_nodes, SHOW_LONG},
808  {"number_of_ready_data_nodes",
809  (char*) &g_ndb_status.number_of_ready_data_nodes, SHOW_LONG},
810  {"connect_count", (char*) &g_ndb_status.connect_count, SHOW_LONG},
811  {"execute_count", (char*) &g_ndb_status.execute_count, SHOW_LONG},
812  {"scan_count", (char*) &g_ndb_status.scan_count, SHOW_LONG},
813  {"pruned_scan_count", (char*) &g_ndb_status.pruned_scan_count, SHOW_LONG},
814  {"schema_locks_count", (char*) &g_ndb_status.schema_locks_count, SHOW_LONG},
815  NDBAPI_COUNTERS("_session", &g_ndb_status.api_client_stats),
816  {"sorted_scan_count", (char*) &g_ndb_status.sorted_scan_count, SHOW_LONG},
817  {"pushed_queries_defined", (char*) &g_ndb_status.pushed_queries_defined,
818  SHOW_LONG},
819  {"pushed_queries_dropped", (char*) &g_ndb_status.pushed_queries_dropped,
820  SHOW_LONG},
821  {"pushed_queries_executed", (char*) &g_ndb_status.pushed_queries_executed,
822  SHOW_LONG},
823  {"pushed_reads", (char*) &g_ndb_status.pushed_reads, SHOW_LONG},
824  {NullS, NullS, SHOW_LONG}
825 };
826 
827 SHOW_VAR ndb_status_conflict_variables[]= {
828  {"fn_max", (char*) &g_ndb_slave_state.total_violation_count[CFT_NDB_MAX], SHOW_LONGLONG},
829  {"fn_old", (char*) &g_ndb_slave_state.total_violation_count[CFT_NDB_OLD], SHOW_LONGLONG},
830  {"fn_max_del_win", (char*) &g_ndb_slave_state.total_violation_count[CFT_NDB_MAX_DEL_WIN], SHOW_LONGLONG},
831  {"fn_epoch", (char*) &g_ndb_slave_state.total_violation_count[CFT_NDB_EPOCH], SHOW_LONGLONG},
832  {NullS, NullS, SHOW_LONG}
833 };
834 
835 SHOW_VAR ndb_status_injector_variables[]= {
836  {"api_event_data_count_injector", (char*) &g_event_data_count, SHOW_LONGLONG},
837  {"api_event_nondata_count_injector", (char*) &g_event_nondata_count, SHOW_LONGLONG},
838  {"api_event_bytes_count_injector", (char*) &g_event_bytes_count, SHOW_LONGLONG},
839  {NullS, NullS, SHOW_LONG}
840 };
841 
842 SHOW_VAR ndb_status_slave_variables[]= {
843  NDBAPI_COUNTERS("_slave", &g_slave_api_client_stats),
844  {"slave_max_replicated_epoch", (char*) &g_ndb_slave_state.max_rep_epoch, SHOW_LONGLONG},
845  {NullS, NullS, SHOW_LONG}
846 };
847 
848 SHOW_VAR ndb_status_server_client_stat_variables[]= {
849  NDBAPI_COUNTERS("", &g_server_api_client_stats),
850  {"api_event_data_count",
851  (char*) &g_server_api_client_stats[ Ndb::DataEventsRecvdCount ],
852  SHOW_LONGLONG},
853  {"api_event_nondata_count",
854  (char*) &g_server_api_client_stats[ Ndb::NonDataEventsRecvdCount ],
855  SHOW_LONGLONG},
856  {"api_event_bytes_count",
857  (char*) &g_server_api_client_stats[ Ndb::EventBytesRecvdCount ],
858  SHOW_LONGLONG},
859  {NullS, NullS, SHOW_LONG}
860 };
861 
862 static int show_ndb_server_api_stats(THD *thd, SHOW_VAR *var, char *buff)
863 {
864  /* This function is called when SHOW STATUS / INFO_SCHEMA wants
865  * to see one of our status vars
866  * We use this opportunity to :
867  * 1) Update the globals with current values
868  * 2) Return an array of var definitions, pointing to
869  * the updated globals
870  */
871  ndb_get_connection_stats((Uint64*) &g_server_api_client_stats[0]);
872 
873  var->type= SHOW_ARRAY;
874  var->value= (char*) ndb_status_server_client_stat_variables;
875 
876  return 0;
877 }
878 
879 SHOW_VAR ndb_status_index_stat_variables[]= {
880  {"cache_query", (char*) &g_ndb_status_index_stat_cache_query, SHOW_LONG},
881  {"cache_clean", (char*) &g_ndb_status_index_stat_cache_clean, SHOW_LONG},
882  {NullS, NullS, SHOW_LONG}
883 };
884 
885 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
886 static int ndbcluster_make_pushed_join(handlerton *, THD*,AQP::Join_plan*);
887 #endif
888 
889 /*
890  Error handling functions
891 */
892 
893 /* Note for merge: old mapping table, moved to storage/ndb/ndberror.c */
894 
895 static int ndb_to_mysql_error(const NdbError *ndberr)
896 {
897  /* read the mysql mapped error code */
898  int error= ndberr->mysql_code;
899 
900  switch (error)
901  {
902  /* errors for which we do not add warnings, just return mapped error code
903  */
904  case HA_ERR_NO_SUCH_TABLE:
905  case HA_ERR_KEY_NOT_FOUND:
906  return error;
907 
908  /* Mapping missing, go with the ndb error code*/
909  case -1:
910  error= ndberr->code;
911  break;
912  /* Mapping exists, go with the mapped code */
913  default:
914  break;
915  }
916 
917  /*
918  If we don't abort directly on warnings push a warning
919  with the internal error information
920  */
921  if (!current_thd->abort_on_warning)
922  {
923  /*
924  Push the NDB error message as warning
925  - Used to be able to use SHOW WARNINGS toget more info on what the error is
926  - Used by replication to see if the error was temporary
927  */
928  if (ndberr->status == NdbError::TemporaryError)
929  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
930  ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG),
931  ndberr->code, ndberr->message, "NDB");
932  else
933  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
934  ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
935  ndberr->code, ndberr->message, "NDB");
936  }
937  return error;
938 }
939 
940 #ifdef HAVE_NDB_BINLOG
941 
942 /* Write conflicting row to exceptions table. */
943 static int write_conflict_row(NDB_SHARE *share,
944  NdbTransaction *trans,
945  const uchar *row,
946  NdbError& err)
947 {
948  DBUG_ENTER("write_conflict_row");
949 
950  /* get exceptions table */
951  NDB_CONFLICT_FN_SHARE *cfn_share= share->m_cfn_share;
952  const NDBTAB *ex_tab= cfn_share->m_ex_tab;
953  DBUG_ASSERT(ex_tab != NULL);
954 
955  /* get insert op */
956  NdbOperation *ex_op= trans->getNdbOperation(ex_tab);
957  if (ex_op == NULL)
958  {
959  err= trans->getNdbError();
960  DBUG_RETURN(-1);
961  }
962  if (ex_op->insertTuple() == -1)
963  {
964  err= ex_op->getNdbError();
965  DBUG_RETURN(-1);
966  }
967  {
968  uint32 server_id= (uint32)::server_id;
969  uint32 master_server_id= (uint32) ndb_mi_get_master_server_id();
970  uint64 master_epoch= (uint64) g_ndb_slave_state.current_master_server_epoch;
971  uint32 count= (uint32)++(cfn_share->m_count);
972  if (ex_op->setValue((Uint32)0, (const char *)&(server_id)) ||
973  ex_op->setValue((Uint32)1, (const char *)&(master_server_id)) ||
974  ex_op->setValue((Uint32)2, (const char *)&(master_epoch)) ||
975  ex_op->setValue((Uint32)3, (const char *)&(count)))
976  {
977  err= ex_op->getNdbError();
978  DBUG_RETURN(-1);
979  }
980  }
981  /* copy primary keys */
982  {
983  const int fixed_cols= 4;
984  int nkey= cfn_share->m_pk_cols;
985  int k;
986  for (k= 0; k < nkey; k++)
987  {
988  DBUG_ASSERT(row != NULL);
989  const uchar* data= row + cfn_share->m_offset[k];
990  if (ex_op->setValue((Uint32)(fixed_cols + k), (const char*)data) == -1)
991  {
992  err= ex_op->getNdbError();
993  DBUG_RETURN(-1);
994  }
995  }
996  }
997  DBUG_RETURN(0);
998 }
999 #endif
1000 
1001 #ifdef HAVE_NDB_BINLOG
1002 int
1003 handle_conflict_op_error(Thd_ndb* thd_ndb,
1004  NdbTransaction* trans,
1005  const NdbError& err,
1006  const NdbOperation* op);
1007 
1008 int
1009 handle_row_conflict(NDB_CONFLICT_FN_SHARE* cfn_share,
1010  const char* tab_name,
1011  const NdbRecord* key_rec,
1012  const uchar* pk_row,
1013  enum_conflicting_op_type op_type,
1014  enum_conflict_cause conflict_cause,
1015  const NdbError& conflict_error,
1016  NdbTransaction* conflict_trans,
1017  NdbError& err);
1018 #endif
1019 
1020 static const Uint32 error_op_after_refresh_op = 920;
1021 
1022 inline int
1023 check_completed_operations_pre_commit(Thd_ndb *thd_ndb, NdbTransaction *trans,
1024  const NdbOperation *first,
1025  const NdbOperation *last,
1026  uint *ignore_count)
1027 {
1028  uint ignores= 0;
1029  DBUG_ENTER("check_completed_operations_pre_commit");
1030 
1031  if (unlikely(first == 0))
1032  {
1033  assert(last == 0);
1034  DBUG_RETURN(0);
1035  }
1036 
1037  /*
1038  Check that all errors are "accepted" errors
1039  or exceptions to report
1040  */
1041 #ifdef HAVE_NDB_BINLOG
1042  const NdbOperation* lastUserOp = trans->getLastDefinedOperation();
1043 #endif
1044  while (true)
1045  {
1046  const NdbError &err= first->getNdbError();
1047  const bool op_has_conflict_detection = (first->getCustomData() != NULL);
1048  if (!op_has_conflict_detection)
1049  {
1050  /* 'Normal path' - ignore key (not) present, others are errors */
1051  if (err.classification != NdbError::NoError &&
1054  {
1055  /* Non ignored error, report it */
1056  DBUG_PRINT("info", ("err.code == %u", err.code));
1057  DBUG_RETURN(err.code);
1058  }
1059  }
1060 #ifdef HAVE_NDB_BINLOG
1061  else
1062  {
1063  /*
1064  Op with conflict detection, use special error handling method
1065  */
1066 
1067  if (err.classification != NdbError::NoError)
1068  {
1069  int res = handle_conflict_op_error(thd_ndb,
1070  trans,
1071  err,
1072  first);
1073  if (res != 0)
1074  DBUG_RETURN(res);
1075  }
1076  } // if (!op_has_conflict_detection)
1077 #endif
1078  if (err.classification != NdbError::NoError)
1079  ignores++;
1080 
1081  if (first == last)
1082  break;
1083 
1084  first= trans->getNextCompletedOperation(first);
1085  }
1086  if (ignore_count)
1087  *ignore_count= ignores;
1088 #ifdef HAVE_NDB_BINLOG
1089  /*
1090  Conflict detection related error handling above may have defined
1091  new operations on the transaction. If so, execute them now
1092  */
1093  if (trans->getLastDefinedOperation() != lastUserOp)
1094  {
1095  const NdbOperation* last_conflict_op = trans->getLastDefinedOperation();
1096 
1097  if (trans->execute(NdbTransaction::NoCommit,
1099  thd_ndb->m_force_send))
1100  {
1101  abort();
1102  //err= trans->getNdbError();
1103  }
1104 
1105  if (trans->getNdbError().code)
1106  {
1107  /* Check the result codes of the operations we added */
1108  const NdbOperation* conflict_op = NULL;
1109  do
1110  {
1111  conflict_op = trans->getNextCompletedOperation(conflict_op);
1112  assert(conflict_op != NULL);
1113  /* We will ignore 920 which represents a refreshOp or other op
1114  * arriving after a refreshOp
1115  */
1116  const NdbError& err = conflict_op->getNdbError();
1117  if ((err.code != 0) &&
1118  (err.code != (int) error_op_after_refresh_op))
1119  {
1120  if (err.status == NdbError::TemporaryError)
1121  {
1122  /* Slave will roll back and retry entire transaction. */
1123  ERR_RETURN(err);
1124  }
1125  else
1126  {
1127  char msg[FN_REFLEN];
1128  my_snprintf(msg, sizeof(msg), "Executing extra operations for "
1129  "conflict handling hit Ndb error %d '%s'",
1130  err.code, err.message);
1131  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_ERROR,
1132  ER_EXCEPTIONS_WRITE_ERROR,
1133  ER(ER_EXCEPTIONS_WRITE_ERROR), msg);
1134  /* Slave will stop replication. */
1135  DBUG_RETURN(ER_EXCEPTIONS_WRITE_ERROR);
1136  }
1137  }
1138  } while (conflict_op != last_conflict_op);
1139  }
1140  }
1141 #endif
1142  DBUG_RETURN(0);
1143 }
1144 
1145 inline int
1146 check_completed_operations(Thd_ndb *thd_ndb, NdbTransaction *trans,
1147  const NdbOperation *first,
1148  const NdbOperation *last,
1149  uint *ignore_count)
1150 {
1151  uint ignores= 0;
1152  DBUG_ENTER("check_completed_operations");
1153 
1154  if (unlikely(first == 0))
1155  {
1156  assert(last == 0);
1157  DBUG_RETURN(0);
1158  }
1159 
1160  /*
1161  Check that all errors are "accepted" errors
1162  */
1163  while (true)
1164  {
1165  const NdbError &err= first->getNdbError();
1166  if (err.classification != NdbError::NoError &&
1169  {
1170 #ifdef HAVE_NDB_BINLOG
1171  /* All conflict detection etc should be done before commit */
1172  DBUG_ASSERT((err.code != (int) error_conflict_fn_violation) &&
1173  (err.code != (int) error_op_after_refresh_op));
1174 #endif
1175  DBUG_RETURN(err.code);
1176  }
1177  if (err.classification != NdbError::NoError)
1178  ignores++;
1179 
1180  if (first == last)
1181  break;
1182 
1183  first= trans->getNextCompletedOperation(first);
1184  }
1185  if (ignore_count)
1186  *ignore_count= ignores;
1187  DBUG_RETURN(0);
1188 }
1189 
1190 void
1191 ha_ndbcluster::release_completed_operations(NdbTransaction *trans)
1192 {
1201  trans->releaseCompletedOperations();
1202  trans->releaseCompletedQueries();
1203 }
1204 
1205 int execute_no_commit(Thd_ndb *thd_ndb, NdbTransaction *trans,
1206  bool ignore_no_key,
1207  uint *ignore_count= 0);
1208 inline
1209 int execute_no_commit(Thd_ndb *thd_ndb, NdbTransaction *trans,
1210  bool ignore_no_key,
1211  uint *ignore_count)
1212 {
1213  DBUG_ENTER("execute_no_commit");
1214  ha_ndbcluster::release_completed_operations(trans);
1215  const NdbOperation *first= trans->getFirstDefinedOperation();
1216  const NdbOperation *last= trans->getLastDefinedOperation();
1217  thd_ndb->m_execute_count++;
1218  thd_ndb->m_unsent_bytes= 0;
1219  DBUG_PRINT("info", ("execute_count: %u", thd_ndb->m_execute_count));
1220  if (trans->execute(NdbTransaction::NoCommit,
1222  thd_ndb->m_force_send))
1223  {
1224  DBUG_RETURN(-1);
1225  }
1226  if (!ignore_no_key || trans->getNdbError().code == 0)
1227  DBUG_RETURN(trans->getNdbError().code);
1228 
1229  DBUG_RETURN(check_completed_operations_pre_commit(thd_ndb, trans,
1230  first, last,
1231  ignore_count));
1232 }
1233 
1234 int execute_commit(THD* thd, Thd_ndb *thd_ndb, NdbTransaction *trans,
1235  int force_send, int ignore_error, uint *ignore_count= 0);
1236 inline
1237 int execute_commit(THD* thd, Thd_ndb *thd_ndb, NdbTransaction *trans,
1238  int force_send, int ignore_error, uint *ignore_count)
1239 {
1240  DBUG_ENTER("execute_commit");
1242  if (thd_ndb->m_unsent_bytes && !ignore_error)
1243  {
1244  /*
1245  We have unsent bytes and cannot ignore error. Calling execute
1246  with NdbOperation::AO_IgnoreError will result in possible commit
1247  of a transaction although there is an error.
1248  */
1250  }
1251  const NdbOperation *first= trans->getFirstDefinedOperation();
1252  const NdbOperation *last= trans->getLastDefinedOperation();
1253  thd_ndb->m_execute_count++;
1254  thd_ndb->m_unsent_bytes= 0;
1255  DBUG_PRINT("info", ("execute_count: %u", thd_ndb->m_execute_count));
1256  if (trans->execute(NdbTransaction::Commit, ao, force_send))
1257  {
1258  if (thd->slave_thread)
1259  g_ndb_slave_state.atTransactionAbort();
1260  DBUG_RETURN(-1);
1261  }
1262  /* Success of some sort */
1263  if (thd->slave_thread)
1264  {
1265  g_ndb_slave_state.atTransactionCommit();
1266  }
1267  if (!ignore_error || trans->getNdbError().code == 0)
1268  DBUG_RETURN(trans->getNdbError().code);
1269  DBUG_RETURN(check_completed_operations(thd_ndb, trans, first, last,
1270  ignore_count));
1271 }
1272 
1273 inline
1274 int execute_no_commit_ie(Thd_ndb *thd_ndb, NdbTransaction *trans)
1275 {
1276  DBUG_ENTER("execute_no_commit_ie");
1277  ha_ndbcluster::release_completed_operations(trans);
1278  int res= trans->execute(NdbTransaction::NoCommit,
1280  thd_ndb->m_force_send);
1281  thd_ndb->m_unsent_bytes= 0;
1282  thd_ndb->m_execute_count++;
1283  DBUG_PRINT("info", ("execute_count: %u", thd_ndb->m_execute_count));
1284  DBUG_RETURN(res);
1285 }
1286 
1287 /*
1288  Place holder for ha_ndbcluster thread specific data
1289 */
1290 typedef struct st_thd_ndb_share {
1291  const void *key;
1292  struct Ndb_local_table_statistics stat;
1293 } THD_NDB_SHARE;
1294 static
1295 uchar *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, size_t *length,
1296  my_bool not_used __attribute__((unused)))
1297 {
1298  *length= sizeof(thd_ndb_share->key);
1299  return (uchar*) &thd_ndb_share->key;
1300 }
1301 
1302 Thd_ndb::Thd_ndb(THD* thd) :
1303  m_thd(thd),
1304  schema_locks_count(0)
1305 {
1306  connection= ndb_get_cluster_connection();
1307  m_connect_count= connection->get_connect_count();
1308  ndb= new Ndb(connection, "");
1309  lock_count= 0;
1310  start_stmt_count= 0;
1311  save_point_count= 0;
1312  count= 0;
1313  trans= NULL;
1314  m_handler= NULL;
1315  m_error= FALSE;
1316  options= 0;
1317  (void) my_hash_init(&open_tables, table_alias_charset, 5, 0, 0,
1318  (my_hash_get_key)thd_ndb_share_get_key, 0, 0);
1319  m_unsent_bytes= 0;
1320  m_execute_count= 0;
1321  m_scan_count= 0;
1322  m_pruned_scan_count= 0;
1323  m_sorted_scan_count= 0;
1324  m_pushed_queries_defined= 0;
1325  m_pushed_queries_dropped= 0;
1326  m_pushed_queries_executed= 0;
1327  m_pushed_reads= 0;
1328  memset(m_transaction_no_hint_count, 0, sizeof(m_transaction_no_hint_count));
1329  memset(m_transaction_hint_count, 0, sizeof(m_transaction_hint_count));
1330  global_schema_lock_trans= NULL;
1331  global_schema_lock_count= 0;
1332  global_schema_lock_error= 0;
1333  init_alloc_root(&m_batch_mem_root, BATCH_FLUSH_SIZE/4, 0);
1334 }
1335 
1336 Thd_ndb::~Thd_ndb()
1337 {
1338  if (opt_ndb_extra_logging > 1)
1339  {
1340  /*
1341  print some stats about the connection at disconnect
1342  */
1343  for (int i= 0; i < MAX_NDB_NODES; i++)
1344  {
1345  if (m_transaction_hint_count[i] > 0 ||
1346  m_transaction_no_hint_count[i] > 0)
1347  {
1348  sql_print_information("tid %u: node[%u] "
1349  "transaction_hint=%u, transaction_no_hint=%u",
1350  (unsigned)current_thd->thread_id, i,
1351  m_transaction_hint_count[i],
1352  m_transaction_no_hint_count[i]);
1353  }
1354  }
1355  }
1356  if (ndb)
1357  {
1358  delete ndb;
1359  ndb= NULL;
1360  }
1361  changed_tables.empty();
1362  my_hash_free(&open_tables);
1363  free_root(&m_batch_mem_root, MYF(0));
1364 }
1365 
1366 
1367 inline
1368 Ndb *ha_ndbcluster::get_ndb(THD *thd)
1369 {
1370  return get_thd_ndb(thd)->ndb;
1371 }
1372 
1373 /*
1374  * manage uncommitted insert/deletes during transactio to get records correct
1375  */
1376 
1377 void ha_ndbcluster::set_rec_per_key()
1378 {
1379  DBUG_ENTER("ha_ndbcluster::set_rec_per_key");
1380  /*
1381  Set up the 'rec_per_key[]' for keys which we have good knowledge
1382  about the distribution. 'rec_per_key[]' is init'ed to '0' by
1383  open_binary_frm(), which is interpreted as 'unknown' by optimizer.
1384  -> Not setting 'rec_per_key[]' will force the optimizer to use
1385  its own heuristic to estimate 'records pr. key'.
1386  */
1387  for (uint i=0 ; i < table_share->keys ; i++)
1388  {
1389  bool is_unique_index= false;
1390  KEY* key_info= table->key_info + i;
1391  switch (get_index_type(i))
1392  {
1393  case UNIQUE_INDEX:
1394  case PRIMARY_KEY_INDEX:
1395  {
1396  // Index is unique when all 'key_parts' are specified,
1397  // else distribution is unknown and not specified here.
1398  is_unique_index= true;
1399  break;
1400  }
1401  case UNIQUE_ORDERED_INDEX:
1402  case PRIMARY_KEY_ORDERED_INDEX:
1403  is_unique_index= true;
1404  // intentional fall thru to logic for ordered index
1405  case ORDERED_INDEX:
1406  // 'Records pr. key' are unknown for non-unique indexes.
1407  // (May change when we get better index statistics.)
1408  {
1409  THD *thd= current_thd;
1410  const bool index_stat_enable= THDVAR(NULL, index_stat_enable) &&
1411  THDVAR(thd, index_stat_enable);
1412  if (index_stat_enable)
1413  {
1414  int err= ndb_index_stat_set_rpk(i);
1415  if (err != 0 &&
1416  /* no stats is not unexpected error */
1417  err != NdbIndexStat::NoIndexStats &&
1418  /* warning was printed at first error */
1419  err != Ndb_index_stat_error_HAS_ERROR)
1420  {
1421  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
1422  ER_CANT_GET_STAT, /* pun? */
1423  "index stats (RPK) for key %s:"
1424  " unexpected error %d",
1425  key_info->name, err);
1426  }
1427  }
1428  // no fallback method...
1429  break;
1430  }
1431  default:
1432  DBUG_ASSERT(false);
1433  }
1434  // set rows per key to 1 for complete key given for unique/primary index
1435  if (is_unique_index)
1436  {
1437  key_info->rec_per_key[key_info->user_defined_key_parts-1]= 1;
1438  }
1439  }
1440  DBUG_VOID_RETURN;
1441 }
1442 
1443 ha_rows ha_ndbcluster::records()
1444 {
1445  DBUG_ENTER("ha_ndbcluster::records");
1446  DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
1447  ((const NDBTAB *)m_table)->getTableId(),
1448  m_table_info->no_uncommitted_rows_count));
1449 
1450  if (update_stats(table->in_use, 1) == 0)
1451  {
1452  DBUG_RETURN(stats.records);
1453  }
1454  else
1455  {
1456  DBUG_RETURN(HA_POS_ERROR);
1457  }
1458 }
1459 
1460 void ha_ndbcluster::no_uncommitted_rows_execute_failure()
1461 {
1462  DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_execute_failure");
1463  get_thd_ndb(current_thd)->m_error= TRUE;
1464  DBUG_VOID_RETURN;
1465 }
1466 
1467 void ha_ndbcluster::no_uncommitted_rows_update(int c)
1468 {
1469  DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_update");
1470  struct Ndb_local_table_statistics *local_info= m_table_info;
1471  local_info->no_uncommitted_rows_count+= c;
1472  DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
1473  ((const NDBTAB *)m_table)->getTableId(),
1474  local_info->no_uncommitted_rows_count));
1475  DBUG_VOID_RETURN;
1476 }
1477 
1478 void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd)
1479 {
1480  DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_reset");
1481  Thd_ndb *thd_ndb= get_thd_ndb(thd);
1482  thd_ndb->count++;
1483  thd_ndb->m_error= FALSE;
1484  thd_ndb->m_unsent_bytes= 0;
1485  DBUG_VOID_RETURN;
1486 }
1487 
1488 
1489 int ha_ndbcluster::ndb_err(NdbTransaction *trans,
1490  bool have_lock)
1491 {
1492  THD *thd= current_thd;
1493  int res;
1494  NdbError err= trans->getNdbError();
1495  DBUG_ENTER("ndb_err");
1496 
1497  switch (err.classification) {
1498  case NdbError::SchemaError:
1499  {
1500  // TODO perhaps we need to do more here, invalidate also in the cache
1501  m_table->setStatusInvalid();
1502  /* Close other open handlers not used by any thread */
1503  TABLE_LIST table_list;
1504  memset(&table_list, 0, sizeof(table_list));
1505  table_list.db= m_dbname;
1506  table_list.alias= table_list.table_name= m_tabname;
1507  close_cached_tables(thd, &table_list, have_lock, FALSE, FALSE);
1508  break;
1509  }
1510  default:
1511  break;
1512  }
1513  res= ndb_to_mysql_error(&err);
1514  DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
1515  err.code, res));
1516  if (res == HA_ERR_FOUND_DUPP_KEY)
1517  {
1518  char *error_data= err.details;
1519  uint dupkey= MAX_KEY;
1520 
1521  for (uint i= 0; i < MAX_KEY; i++)
1522  {
1523  if (m_index[i].type == UNIQUE_INDEX ||
1524  m_index[i].type == UNIQUE_ORDERED_INDEX)
1525  {
1526  const NDBINDEX *unique_index=
1527  (const NDBINDEX *) m_index[i].unique_index;
1528  if (unique_index &&
1529  (char *) unique_index->getObjectId() == error_data)
1530  {
1531  dupkey= i;
1532  break;
1533  }
1534  }
1535  }
1536  if (m_rows_to_insert == 1)
1537  {
1538  /*
1539  We can only distinguish between primary and non-primary
1540  violations here, so we need to return MAX_KEY for non-primary
1541  to signal that key is unknown
1542  */
1543  m_dupkey= err.code == 630 ? table_share->primary_key : dupkey;
1544  }
1545  else
1546  {
1547  /* We are batching inserts, offending key is not available */
1548  m_dupkey= (uint) -1;
1549  }
1550  }
1551  DBUG_RETURN(res);
1552 }
1553 
1554 
1560 bool ha_ndbcluster::get_error_message(int error,
1561  String *buf)
1562 {
1563  DBUG_ENTER("ha_ndbcluster::get_error_message");
1564  DBUG_PRINT("enter", ("error: %d", error));
1565 
1566  Ndb *ndb= check_ndb_in_thd(current_thd);
1567  if (!ndb)
1568  DBUG_RETURN(FALSE);
1569 
1570  const NdbError err= ndb->getNdbError(error);
1571  bool temporary= err.status==NdbError::TemporaryError;
1572  buf->set(err.message, strlen(err.message), &my_charset_bin);
1573  DBUG_PRINT("exit", ("message: %s, temporary: %d", buf->ptr(), temporary));
1574  DBUG_RETURN(temporary);
1575 }
1576 
1577 
1578 /*
1579  field_used_length() returns the number of bytes actually used to
1580  store the data of the field. So for a varstring it includes both
1581  length byte(s) and string data, and anything after data_length()
1582  bytes are unused.
1583 */
1584 static
1585 uint32 field_used_length(const Field* field)
1586 {
1587  if (field->type() == MYSQL_TYPE_VARCHAR)
1588  {
1589  const Field_varstring* f = static_cast<const Field_varstring*>(field);
1590  return f->length_bytes + const_cast<Field_varstring*>(f)->data_length();
1591  // ^ no 'data_length() const'
1592  }
1593  return field->pack_length();
1594 }
1595 
1596 
1600 static bool field_type_forces_var_part(enum_field_types type)
1601 {
1602  switch (type) {
1603  case MYSQL_TYPE_VAR_STRING:
1604  case MYSQL_TYPE_VARCHAR:
1605  return TRUE;
1606  case MYSQL_TYPE_TINY_BLOB:
1607  case MYSQL_TYPE_BLOB:
1608  case MYSQL_TYPE_MEDIUM_BLOB:
1609  case MYSQL_TYPE_LONG_BLOB:
1610  case MYSQL_TYPE_GEOMETRY:
1611  return FALSE;
1612  default:
1613  return FALSE;
1614  }
1615 }
1616 
1617 /*
1618  * This is used for every additional row operation, to update the guesstimate
1619  * of pending bytes to send, and to check if it is now time to flush a batch.
1620  */
1621 bool
1622 ha_ndbcluster::add_row_check_if_batch_full_size(Thd_ndb *thd_ndb, uint size)
1623 {
1624  if (thd_ndb->m_unsent_bytes == 0)
1625  free_root(&(thd_ndb->m_batch_mem_root), MY_MARK_BLOCKS_FREE);
1626 
1627  uint unsent= thd_ndb->m_unsent_bytes;
1628  unsent+= size;
1629  thd_ndb->m_unsent_bytes= unsent;
1630  return unsent >= thd_ndb->m_batch_size;
1631 }
1632 
1633 /*
1634  Return a generic buffer that will remain valid until after next execute.
1635 
1636  The memory is freed by the first call to add_row_check_if_batch_full_size()
1637  following any execute() call. The intention is that the memory is associated
1638  with one batch of operations during batched slave updates.
1639 
1640  Note in particular that using get_buffer() / copy_row_to_buffer() separately
1641  from add_row_check_if_batch_full_size() could make meory usage grow without
1642  limit, and that this sequence:
1643 
1644  execute()
1645  get_buffer() / copy_row_to_buffer()
1646  add_row_check_if_batch_full_size()
1647  ...
1648  execute()
1649 
1650  will free the memory already at add_row_check_if_batch_full_size() time, it
1651  will not remain valid until the second execute().
1652 */
1653 uchar *
1654 ha_ndbcluster::get_buffer(Thd_ndb *thd_ndb, uint size)
1655 {
1656  return (uchar*)alloc_root(&(thd_ndb->m_batch_mem_root), size);
1657 }
1658 
1659 uchar *
1660 ha_ndbcluster::copy_row_to_buffer(Thd_ndb *thd_ndb, const uchar *record)
1661 {
1662  uchar *row= get_buffer(thd_ndb, table->s->reclength);
1663  if (unlikely(!row))
1664  return NULL;
1665  memcpy(row, record, table->s->reclength);
1666  return row;
1667 }
1668 
1675 int findBlobError(NdbError& error, NdbBlob* pBlob)
1676 {
1677  error= pBlob->getNdbError();
1678  if (error.code != 0)
1679  return 0;
1680 
1681  const NdbOperation* pOp= pBlob->getNdbOperation();
1682  error= pOp->getNdbError();
1683  if (error.code != 0)
1684  return 0;
1685 
1686  NdbTransaction* pTrans= pOp->getNdbTransaction();
1687  error= pTrans->getNdbError();
1688  if (error.code != 0)
1689  return 0;
1690 
1691  /* No error on any of the objects */
1692  return -1;
1693 }
1694 
1695 
1696 int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg)
1697 {
1698  ha_ndbcluster *ha= (ha_ndbcluster *)arg;
1699  DBUG_ENTER("g_get_ndb_blobs_value");
1700  DBUG_PRINT("info", ("destination row: %p", ha->m_blob_destination_record));
1701 
1702  if (ha->m_blob_counter == 0) /* Reset total size at start of row */
1703  ha->m_blobs_row_total_size= 0;
1704 
1705  /* Count the total length needed for blob data. */
1706  int isNull;
1707  if (ndb_blob->getNull(isNull) != 0)
1708  ERR_RETURN(ndb_blob->getNdbError());
1709  if (isNull == 0) {
1710  Uint64 len64= 0;
1711  if (ndb_blob->getLength(len64) != 0)
1712  ERR_RETURN(ndb_blob->getNdbError());
1713  /* Align to Uint64. */
1714  ha->m_blobs_row_total_size+= (len64 + 7) & ~((Uint64)7);
1715  if (ha->m_blobs_row_total_size > 0xffffffff)
1716  {
1717  DBUG_ASSERT(FALSE);
1718  DBUG_RETURN(-1);
1719  }
1720  DBUG_PRINT("info", ("Blob number %d needs size %llu, total buffer reqt. now %llu",
1721  ha->m_blob_counter,
1722  len64,
1723  ha->m_blobs_row_total_size));
1724  }
1725  ha->m_blob_counter++;
1726 
1727  /*
1728  Wait until all blobs in this row are active, so we can allocate
1729  and use a common buffer containing all.
1730  */
1731  if (ha->m_blob_counter < ha->m_blob_expected_count_per_row)
1732  DBUG_RETURN(0);
1733 
1734  /* Reset blob counter for next row (scan scenario) */
1735  ha->m_blob_counter= 0;
1736 
1737  /* Re-allocate bigger blob buffer for this row if necessary. */
1738  if (ha->m_blobs_row_total_size > ha->m_blobs_buffer_size)
1739  {
1740  my_free(ha->m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
1741  DBUG_PRINT("info", ("allocate blobs buffer size %u",
1742  (uint32)(ha->m_blobs_row_total_size)));
1743  /* Windows compiler complains about my_malloc on non-size_t
1744  * validate mapping from Uint64 to size_t
1745  */
1746  if(((size_t)ha->m_blobs_row_total_size) != ha->m_blobs_row_total_size)
1747  {
1748  ha->m_blobs_buffer= NULL;
1749  ha->m_blobs_buffer_size= 0;
1750  DBUG_RETURN(-1);
1751  }
1752 
1753  ha->m_blobs_buffer=
1754  (uchar*) my_malloc((size_t) ha->m_blobs_row_total_size, MYF(MY_WME));
1755  if (ha->m_blobs_buffer == NULL)
1756  {
1757  ha->m_blobs_buffer_size= 0;
1758  DBUG_RETURN(-1);
1759  }
1760  ha->m_blobs_buffer_size= ha->m_blobs_row_total_size;
1761  }
1762 
1763  /*
1764  Now read all blob data.
1765  If we know the destination mysqld row, we also set the blob null bit and
1766  pointer/length (if not, it will be done instead in unpack_record()).
1767  */
1768  uint32 offset= 0;
1769  for (uint i= 0; i < ha->table->s->fields; i++)
1770  {
1771  Field *field= ha->table->field[i];
1772  if (! (field->flags & BLOB_FLAG))
1773  continue;
1774  NdbValue value= ha->m_value[i];
1775  if (value.blob == NULL)
1776  {
1777  DBUG_PRINT("info",("[%u] skipped", i));
1778  continue;
1779  }
1780  Field_blob *field_blob= (Field_blob *)field;
1781  NdbBlob *ndb_blob= value.blob;
1782  int isNull;
1783  if (ndb_blob->getNull(isNull) != 0)
1784  ERR_RETURN(ndb_blob->getNdbError());
1785  if (isNull == 0) {
1786  Uint64 len64= 0;
1787  if (ndb_blob->getLength(len64) != 0)
1788  ERR_RETURN(ndb_blob->getNdbError());
1789  DBUG_ASSERT(len64 < 0xffffffff);
1790  uchar *buf= ha->m_blobs_buffer + offset;
1791  uint32 len= (uint32)(ha->m_blobs_buffer_size - offset);
1792  if (ndb_blob->readData(buf, len) != 0)
1793  {
1794  NdbError err;
1795  if (findBlobError(err, ndb_blob) == 0)
1796  {
1797  ERR_RETURN(err);
1798  }
1799  else
1800  {
1801  /* Should always have some error code set */
1802  assert(err.code != 0);
1803  ERR_RETURN(err);
1804  }
1805  }
1806  DBUG_PRINT("info", ("[%u] offset: %u buf: 0x%lx len=%u",
1807  i, offset, (long) buf, len));
1808  DBUG_ASSERT(len == len64);
1809  if (ha->m_blob_destination_record)
1810  {
1811  my_ptrdiff_t ptrdiff=
1812  ha->m_blob_destination_record - ha->table->record[0];
1813  field_blob->move_field_offset(ptrdiff);
1814  field_blob->set_ptr(len, buf);
1815  field_blob->set_notnull();
1816  field_blob->move_field_offset(-ptrdiff);
1817  }
1818  offset+= Uint32((len64 + 7) & ~((Uint64)7));
1819  }
1820  else if (ha->m_blob_destination_record)
1821  {
1822  /* Have to set length even in this case. */
1823  my_ptrdiff_t ptrdiff=
1824  ha->m_blob_destination_record - ha->table->record[0];
1825  uchar *buf= ha->m_blobs_buffer + offset;
1826  field_blob->move_field_offset(ptrdiff);
1827  field_blob->set_ptr((uint32)0, buf);
1828  field_blob->set_null();
1829  field_blob->move_field_offset(-ptrdiff);
1830  DBUG_PRINT("info", ("[%u] isNull=%d", i, isNull));
1831  }
1832  }
1833 
1834  if (!ha->m_active_cursor)
1835  {
1836  /* Non-scan, Blob reads have been issued
1837  * execute them and then close the Blob
1838  * handles
1839  */
1840  for (uint i= 0; i < ha->table->s->fields; i++)
1841  {
1842  Field *field= ha->table->field[i];
1843  if (! (field->flags & BLOB_FLAG))
1844  continue;
1845  NdbValue value= ha->m_value[i];
1846  if (value.blob == NULL)
1847  {
1848  DBUG_PRINT("info",("[%u] skipped", i));
1849  continue;
1850  }
1851  NdbBlob *ndb_blob= value.blob;
1852 
1853  assert(ndb_blob->getState() == NdbBlob::Active);
1854 
1855  /* Call close() with execPendingBlobOps == true
1856  * For LM_CommittedRead access, this will enqueue
1857  * an unlock operation, which the Blob framework
1858  * code invoking this callback will execute before
1859  * returning control to the caller of execute()
1860  */
1861  if (ndb_blob->close(true) != 0)
1862  {
1863  ERR_RETURN(ndb_blob->getNdbError());
1864  }
1865  }
1866  }
1867 
1868  DBUG_RETURN(0);
1869 }
1870 
1871 /*
1872  Request reading of blob values.
1873 
1874  If dst_record is specified, the blob null bit, pointer, and length will be
1875  set in that record. Otherwise they must be set later by calling
1876  unpack_record().
1877 */
1878 int
1879 ha_ndbcluster::get_blob_values(const NdbOperation *ndb_op, uchar *dst_record,
1880  const MY_BITMAP *bitmap)
1881 {
1882  uint i;
1883  DBUG_ENTER("ha_ndbcluster::get_blob_values");
1884 
1885  m_blob_counter= 0;
1886  m_blob_expected_count_per_row= 0;
1887  m_blob_destination_record= dst_record;
1888  m_blobs_row_total_size= 0;
1889  ndb_op->getNdbTransaction()->
1890  setMaxPendingBlobReadBytes(THDVAR(current_thd, blob_read_batch_bytes));
1891 
1892  for (i= 0; i < table_share->fields; i++)
1893  {
1894  Field *field= table->field[i];
1895  if (!(field->flags & BLOB_FLAG))
1896  continue;
1897 
1898  DBUG_PRINT("info", ("fieldnr=%d", i));
1899  NdbBlob *ndb_blob;
1900  if (bitmap_is_set(bitmap, i))
1901  {
1902  if ((ndb_blob= ndb_op->getBlobHandle(i)) == NULL ||
1903  ndb_blob->setActiveHook(g_get_ndb_blobs_value, this) != 0)
1904  DBUG_RETURN(1);
1905  m_blob_expected_count_per_row++;
1906  }
1907  else
1908  ndb_blob= NULL;
1909 
1910  m_value[i].blob= ndb_blob;
1911  }
1912 
1913  DBUG_RETURN(0);
1914 }
1915 
1916 int
1917 ha_ndbcluster::set_blob_values(const NdbOperation *ndb_op,
1918  my_ptrdiff_t row_offset, const MY_BITMAP *bitmap,
1919  uint *set_count, bool batch)
1920 {
1921  uint field_no;
1922  uint *blob_index, *blob_index_end;
1923  int res= 0;
1924  DBUG_ENTER("ha_ndbcluster::set_blob_values");
1925 
1926  *set_count= 0;
1927 
1928  if (table_share->blob_fields == 0)
1929  DBUG_RETURN(0);
1930 
1931  ndb_op->getNdbTransaction()->
1932  setMaxPendingBlobWriteBytes(THDVAR(current_thd, blob_write_batch_bytes));
1933  blob_index= table_share->blob_field;
1934  blob_index_end= blob_index + table_share->blob_fields;
1935  do
1936  {
1937  field_no= *blob_index;
1938  /* A NULL bitmap sets all blobs. */
1939  if (bitmap && !bitmap_is_set(bitmap, field_no))
1940  continue;
1941  Field *field= table->field[field_no];
1942 
1943  NdbBlob *ndb_blob= ndb_op->getBlobHandle(field_no);
1944  if (ndb_blob == NULL)
1945  ERR_RETURN(ndb_op->getNdbError());
1946  if (field->is_real_null(row_offset))
1947  {
1948  DBUG_PRINT("info", ("Setting Blob %d to NULL", field_no));
1949  if (ndb_blob->setNull() != 0)
1950  ERR_RETURN(ndb_op->getNdbError());
1951  }
1952  else
1953  {
1954  Field_blob *field_blob= (Field_blob *)field;
1955 
1956  // Get length and pointer to data
1957  const uchar *field_ptr= field->ptr + row_offset;
1958  uint32 blob_len= field_blob->get_length(field_ptr);
1959  uchar* blob_ptr= NULL;
1960  field_blob->get_ptr(&blob_ptr);
1961 
1962  // Looks like NULL ptr signals length 0 blob
1963  if (blob_ptr == NULL) {
1964  DBUG_ASSERT(blob_len == 0);
1965  blob_ptr= (uchar*)"";
1966  }
1967 
1968  DBUG_PRINT("value", ("set blob ptr: 0x%lx len: %u",
1969  (long) blob_ptr, blob_len));
1970  DBUG_DUMP("value", blob_ptr, MIN(blob_len, 26));
1971 
1972  /*
1973  NdbBlob requires the data pointer to remain valid until execute() time.
1974  So when batching, we need to copy the value to a temporary buffer.
1975  */
1976  if (batch && blob_len > 0)
1977  {
1978  uchar *tmp_buf= get_buffer(m_thd_ndb, blob_len);
1979  if (!tmp_buf)
1980  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
1981  memcpy(tmp_buf, blob_ptr, blob_len);
1982  blob_ptr= tmp_buf;
1983  }
1984  res= ndb_blob->setValue((char*)blob_ptr, blob_len);
1985  if (res != 0)
1986  ERR_RETURN(ndb_op->getNdbError());
1987  }
1988 
1989  ++(*set_count);
1990  } while (++blob_index != blob_index_end);
1991 
1992  DBUG_RETURN(res);
1993 }
1994 
1995 /*
1996  This routine is shared by injector. There is no common blobs buffer
1997  so the buffer and length are passed by reference. Injector also
1998  passes a record pointer diff.
1999  */
2000 int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
2001  uchar*& buffer, uint& buffer_size,
2002  my_ptrdiff_t ptrdiff)
2003 {
2004  DBUG_ENTER("get_ndb_blobs_value");
2005 
2006  // Field has no field number so cannot use TABLE blob_field
2007  // Loop twice, first only counting total buffer size
2008  for (int loop= 0; loop <= 1; loop++)
2009  {
2010  uint32 offset= 0;
2011  for (uint i= 0; i < table->s->fields; i++)
2012  {
2013  Field *field= table->field[i];
2014  NdbValue value= value_array[i];
2015  if (! (field->flags & BLOB_FLAG))
2016  continue;
2017  if (value.blob == NULL)
2018  {
2019  DBUG_PRINT("info",("[%u] skipped", i));
2020  continue;
2021  }
2022  Field_blob *field_blob= (Field_blob *)field;
2023  NdbBlob *ndb_blob= value.blob;
2024  int isNull;
2025  if (ndb_blob->getNull(isNull) != 0)
2026  ERR_RETURN(ndb_blob->getNdbError());
2027  if (isNull == 0) {
2028  Uint64 len64= 0;
2029  if (ndb_blob->getLength(len64) != 0)
2030  ERR_RETURN(ndb_blob->getNdbError());
2031  // Align to Uint64
2032  uint32 size= Uint32(len64);
2033  if (size % 8 != 0)
2034  size+= 8 - size % 8;
2035  if (loop == 1)
2036  {
2037  uchar *buf= buffer + offset;
2038  uint32 len= 0xffffffff; // Max uint32
2039  if (ndb_blob->readData(buf, len) != 0)
2040  ERR_RETURN(ndb_blob->getNdbError());
2041  DBUG_PRINT("info", ("[%u] offset: %u buf: 0x%lx len=%u [ptrdiff=%d]",
2042  i, offset, (long) buf, len, (int)ptrdiff));
2043  DBUG_ASSERT(len == len64);
2044  // Ugly hack assumes only ptr needs to be changed
2045  field_blob->set_ptr_offset(ptrdiff, len, buf);
2046  }
2047  offset+= size;
2048  }
2049  else if (loop == 1) // undefined or null
2050  {
2051  // have to set length even in this case
2052  uchar *buf= buffer + offset; // or maybe NULL
2053  uint32 len= 0;
2054  field_blob->set_ptr_offset(ptrdiff, len, buf);
2055  DBUG_PRINT("info", ("[%u] isNull=%d", i, isNull));
2056  }
2057  }
2058  if (loop == 0 && offset > buffer_size)
2059  {
2060  my_free(buffer, MYF(MY_ALLOW_ZERO_PTR));
2061  buffer_size= 0;
2062  DBUG_PRINT("info", ("allocate blobs buffer size %u", offset));
2063  buffer= (uchar*) my_malloc(offset, MYF(MY_WME));
2064  if (buffer == NULL)
2065  {
2066  sql_print_error("ha_ndbcluster::get_ndb_blobs_value: "
2067  "my_malloc(%u) failed", offset);
2068  DBUG_RETURN(-1);
2069  }
2070  buffer_size= offset;
2071  }
2072  }
2073  DBUG_RETURN(0);
2074 }
2075 
2076 
2081 bool ha_ndbcluster::uses_blob_value(const MY_BITMAP *bitmap) const
2082 {
2083  uint *blob_index, *blob_index_end;
2084  if (table_share->blob_fields == 0)
2085  return FALSE;
2086 
2087  blob_index= table_share->blob_field;
2088  blob_index_end= blob_index + table_share->blob_fields;
2089  do
2090  {
2091  if (bitmap_is_set(bitmap, table->field[*blob_index]->field_index))
2092  return TRUE;
2093  } while (++blob_index != blob_index_end);
2094  return FALSE;
2095 }
2096 
2097 void ha_ndbcluster::release_blobs_buffer()
2098 {
2099  DBUG_ENTER("releaseBlobsBuffer");
2100  if (m_blobs_buffer_size > 0)
2101  {
2102  DBUG_PRINT("info", ("Deleting blobs buffer, size %llu", m_blobs_buffer_size));
2103  my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
2104  m_blobs_buffer= 0;
2105  m_blobs_row_total_size= 0;
2106  m_blobs_buffer_size= 0;
2107  }
2108  DBUG_VOID_RETURN;
2109 }
2110 
2123 int cmp_frm(const NDBTAB *ndbtab, const void *pack_data,
2124  uint pack_length)
2125 {
2126  DBUG_ENTER("cmp_frm");
2127  /*
2128  Compare FrmData in NDB with frm file from disk.
2129  */
2130  if ((pack_length != ndbtab->getFrmLength()) ||
2131  (memcmp(pack_data, ndbtab->getFrmData(), pack_length)))
2132  DBUG_RETURN(1);
2133  DBUG_RETURN(0);
2134 }
2135 
2136 /*
2137  Does type support a default value?
2138 */
2139 static bool
2140 type_supports_default_value(enum_field_types mysql_type)
2141 {
2142  bool ret = (mysql_type != MYSQL_TYPE_BLOB &&
2143  mysql_type != MYSQL_TYPE_TINY_BLOB &&
2144  mysql_type != MYSQL_TYPE_MEDIUM_BLOB &&
2145  mysql_type != MYSQL_TYPE_LONG_BLOB &&
2146  mysql_type != MYSQL_TYPE_GEOMETRY);
2147 
2148  return ret;
2149 }
2150 
2160 int ha_ndbcluster::check_default_values(const NDBTAB* ndbtab)
2161 {
2162  /* Debug only method for checking table defaults aligned
2163  between MySQLD and Ndb
2164  */
2165  bool defaults_aligned= true;
2166 
2167  if (ndbtab->hasDefaultValues())
2168  {
2169  /* Ndb supports native defaults for non-pk columns */
2170  my_bitmap_map *old_map= tmp_use_all_columns(table, table->read_set);
2171 
2172  for (uint f=0; f < table_share->fields; f++)
2173  {
2174  Field* field= table->field[f]; // Use Field struct from MySQLD table rep
2175  const NdbDictionary::Column* ndbCol= ndbtab->getColumn(field->field_index);
2176 
2177  if ((! (field->flags & (PRI_KEY_FLAG |
2178  NO_DEFAULT_VALUE_FLAG))) &&
2179  type_supports_default_value(field->real_type()))
2180  {
2181  /* We expect Ndb to have a native default for this
2182  * column
2183  */
2184  my_ptrdiff_t src_offset= table_share->default_values -
2185  field->table->record[0];
2186 
2187  /* Move field by offset to refer to default value */
2188  field->move_field_offset(src_offset);
2189 
2190  const uchar* ndb_default= (const uchar*) ndbCol->getDefaultValue();
2191 
2192  if (ndb_default == NULL)
2193  /* MySQLD default must also be NULL */
2194  defaults_aligned= field->is_null();
2195  else
2196  {
2197  if (field->type() != MYSQL_TYPE_BIT)
2198  {
2199  defaults_aligned= (0 == field->cmp(ndb_default));
2200  }
2201  else
2202  {
2203  longlong value= (static_cast<Field_bit*>(field))->val_int();
2204  /* Map to NdbApi format - two Uint32s */
2205  Uint32 out[2];
2206  out[0] = 0;
2207  out[1] = 0;
2208  for (int b=0; b < 64; b++)
2209  {
2210  out[b >> 5] |= (value & 1) << (b & 31);
2211 
2212  value= value >> 1;
2213  }
2214  Uint32 defaultLen = field_used_length(field);
2215  defaultLen = ((defaultLen + 3) & ~(Uint32)0x7);
2216  defaults_aligned= (0 == memcmp(ndb_default,
2217  out,
2218  defaultLen));
2219  }
2220  }
2221 
2222  field->move_field_offset(-src_offset);
2223 
2224  if (unlikely(!defaults_aligned))
2225  {
2226  DBUG_PRINT("info", ("Default values differ for column %u",
2227  field->field_index));
2228  break;
2229  }
2230  }
2231  else
2232  {
2233  /* We don't expect Ndb to have a native default for this column */
2234  if (unlikely(ndbCol->getDefaultValue() != NULL))
2235  {
2236  /* Didn't expect that */
2237  DBUG_PRINT("info", ("Column %u has native default, but shouldn't."
2238  " Flags=%u, type=%u",
2239  field->field_index, field->flags, field->real_type()));
2240  defaults_aligned= false;
2241  break;
2242  }
2243  }
2244  }
2245  tmp_restore_column_map(table->read_set, old_map);
2246  }
2247 
2248  return (defaults_aligned? 0: -1);
2249 }
2250 
2251 int ha_ndbcluster::get_metadata(THD *thd, const char *path)
2252 {
2253  Ndb *ndb= get_thd_ndb(thd)->ndb;
2254  NDBDICT *dict= ndb->getDictionary();
2255  const NDBTAB *tab;
2256  int error;
2257  DBUG_ENTER("get_metadata");
2258  DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path));
2259 
2260  DBUG_ASSERT(m_table == NULL);
2261  DBUG_ASSERT(m_table_info == NULL);
2262 
2263  uchar *data= NULL, *pack_data= NULL;
2264  size_t length, pack_length;
2265 
2266  /*
2267  Compare FrmData in NDB with frm file from disk.
2268  */
2269  error= 0;
2270  if (readfrm(path, &data, &length) ||
2271  packfrm(data, length, &pack_data, &pack_length))
2272  {
2273  my_free(data, MYF(MY_ALLOW_ZERO_PTR));
2274  my_free(pack_data, MYF(MY_ALLOW_ZERO_PTR));
2275  DBUG_RETURN(1);
2276  }
2277 
2278  ndb->setDatabaseName(m_dbname);
2279  Ndb_table_guard ndbtab_g(dict, m_tabname);
2280  if (!(tab= ndbtab_g.get_table()))
2281  ERR_RETURN(dict->getNdbError());
2282 
2283  if (get_ndb_share_state(m_share) != NSS_ALTERED
2284  && cmp_frm(tab, pack_data, pack_length))
2285  {
2286  DBUG_PRINT("error",
2287  ("metadata, pack_length: %lu getFrmLength: %d memcmp: %d",
2288  (ulong) pack_length, tab->getFrmLength(),
2289  memcmp(pack_data, tab->getFrmData(), pack_length)));
2290  DBUG_DUMP("pack_data", (uchar*) pack_data, pack_length);
2291  DBUG_DUMP("frm", (uchar*) tab->getFrmData(), tab->getFrmLength());
2292  error= HA_ERR_TABLE_DEF_CHANGED;
2293  }
2294  my_free((char*)data, MYF(0));
2295  my_free((char*)pack_data, MYF(0));
2296 
2297  /* Now check that any Ndb native defaults are aligned
2298  with MySQLD defaults
2299  */
2300  DBUG_ASSERT(check_default_values(tab) == 0);
2301 
2302  if (error)
2303  goto err;
2304 
2305  DBUG_PRINT("info", ("fetched table %s", tab->getName()));
2306  m_table= tab;
2307 
2308  if (bitmap_init(&m_bitmap, m_bitmap_buf, table_share->fields, 0))
2309  {
2310  error= HA_ERR_OUT_OF_MEM;
2311  goto err;
2312  }
2313  if (table_share->primary_key == MAX_KEY)
2314  {
2315  /* Hidden primary key. */
2316  if ((error= add_hidden_pk_ndb_record(dict)) != 0)
2317  goto err;
2318  }
2319 
2320  if ((error= add_table_ndb_record(dict)) != 0)
2321  goto err;
2322 
2323  /*
2324  Approx. write size in bytes over transporter
2325  */
2326  m_bytes_per_write= 12 + tab->getRowSizeInBytes() + 4 * tab->getNoOfColumns();
2327 
2328  /* Open indexes */
2329  if ((error= open_indexes(thd, ndb, table, FALSE)) != 0)
2330  goto err;
2331 
2332  /*
2333  Backward compatibility for tables created without tablespace
2334  in .frm => read tablespace setting from engine
2335  */
2336  if (table_share->mysql_version < 50120 &&
2337  !table_share->tablespace /* safety */)
2338  {
2339  Uint32 id;
2340  if (tab->getTablespace(&id))
2341  {
2342  NdbDictionary::Tablespace ts= dict->getTablespace(id);
2343  NdbError ndberr= dict->getNdbError();
2344  if (ndberr.classification == NdbError::NoError)
2345  {
2346  const char *tablespace= ts.getName();
2347  const size_t tablespace_len= strlen(tablespace);
2348  if (tablespace_len != 0)
2349  {
2350  DBUG_PRINT("info", ("Found tablespace '%s'", tablespace));
2351  table_share->tablespace= strmake_root(&table_share->mem_root,
2352  tablespace,
2353  tablespace_len);
2354  }
2355  }
2356  }
2357  }
2358 
2359  ndbtab_g.release();
2360 
2361 #ifdef HAVE_NDB_BINLOG
2362  ndbcluster_read_binlog_replication(thd, ndb, m_share, m_table,
2363  ::server_id, table, FALSE);
2364 #endif
2365 
2366  DBUG_RETURN(0);
2367 
2368 err:
2369  ndbtab_g.invalidate();
2370  m_table= NULL;
2371  DBUG_RETURN(error);
2372 }
2373 
2374 static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
2375  const NDBINDEX *index,
2376  KEY *key_info)
2377 {
2378  DBUG_ENTER("fix_unique_index_attr_order");
2379  unsigned sz= index->getNoOfIndexColumns();
2380 
2381  if (data.unique_index_attrid_map)
2382  my_free((char*)data.unique_index_attrid_map, MYF(0));
2383  data.unique_index_attrid_map= (uchar*)my_malloc(sz,MYF(MY_WME));
2384  if (data.unique_index_attrid_map == 0)
2385  {
2386  sql_print_error("fix_unique_index_attr_order: my_malloc(%u) failure",
2387  (unsigned int)sz);
2388  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
2389  }
2390 
2391  KEY_PART_INFO* key_part= key_info->key_part;
2392  KEY_PART_INFO* end= key_part+key_info->user_defined_key_parts;
2393  DBUG_ASSERT(key_info->user_defined_key_parts == sz);
2394  for (unsigned i= 0; key_part != end; key_part++, i++)
2395  {
2396  const char *field_name= key_part->field->field_name;
2397 #ifndef DBUG_OFF
2398  data.unique_index_attrid_map[i]= 255;
2399 #endif
2400  for (unsigned j= 0; j < sz; j++)
2401  {
2402  const NDBCOL *c= index->getColumn(j);
2403  if (strcmp(field_name, c->getName()) == 0)
2404  {
2405  data.unique_index_attrid_map[i]= j;
2406  break;
2407  }
2408  }
2409  DBUG_ASSERT(data.unique_index_attrid_map[i] != 255);
2410  }
2411  DBUG_RETURN(0);
2412 }
2413 
2414 /*
2415  Create all the indexes for a table.
2416  If any index should fail to be created,
2417  the error is returned immediately
2418 */
2419 int ha_ndbcluster::create_indexes(THD *thd, Ndb *ndb, TABLE *tab)
2420 {
2421  uint i;
2422  int error= 0;
2423  const char *index_name;
2424  KEY* key_info= tab->key_info;
2425  const char **key_name= tab->s->keynames.type_names;
2426  DBUG_ENTER("ha_ndbcluster::create_indexes");
2427 
2428  for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
2429  {
2430  index_name= *key_name;
2431  NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
2432  error= create_index(thd, index_name, key_info, idx_type, i);
2433  if (error)
2434  {
2435  DBUG_PRINT("error", ("Failed to create index %u", i));
2436  break;
2437  }
2438  }
2439 
2440  DBUG_RETURN(error);
2441 }
2442 
2443 static void ndb_init_index(NDB_INDEX_DATA &data)
2444 {
2445  data.type= UNDEFINED_INDEX;
2446  data.status= UNDEFINED;
2447  data.unique_index= NULL;
2448  data.index= NULL;
2449  data.unique_index_attrid_map= NULL;
2450  data.ndb_record_key= NULL;
2451  data.ndb_unique_record_key= NULL;
2452  data.ndb_unique_record_row= NULL;
2453 }
2454 
2455 static void ndb_clear_index(NDBDICT *dict, NDB_INDEX_DATA &data)
2456 {
2457  if (data.unique_index_attrid_map)
2458  {
2459  my_free((char*)data.unique_index_attrid_map, MYF(0));
2460  }
2461  if (data.ndb_unique_record_key)
2462  dict->releaseRecord(data.ndb_unique_record_key);
2463  if (data.ndb_unique_record_row)
2464  dict->releaseRecord(data.ndb_unique_record_row);
2465  if (data.ndb_record_key)
2466  dict->releaseRecord(data.ndb_record_key);
2467  ndb_init_index(data);
2468 }
2469 
2470 static
2471 void ndb_protect_char(const char* from, char* to, uint to_length, char protect)
2472 {
2473  uint fpos= 0, tpos= 0;
2474 
2475  while(from[fpos] != '\0' && tpos < to_length - 1)
2476  {
2477  if (from[fpos] == protect)
2478  {
2479  int len= 0;
2480  to[tpos++]= '@';
2481  if(tpos < to_length - 5)
2482  {
2483  len= sprintf(to+tpos, "00%u", (uint) protect);
2484  tpos+= len;
2485  }
2486  }
2487  else
2488  {
2489  to[tpos++]= from[fpos];
2490  }
2491  fpos++;
2492  }
2493  to[tpos]= '\0';
2494 }
2495 
2496 /*
2497  Associate a direct reference to an index handle
2498  with an index (for faster access)
2499  */
2500 int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info,
2501  const char *key_name, uint index_no)
2502 {
2503  char index_name[FN_LEN + 1];
2504  int error= 0;
2505 
2506  NDB_INDEX_TYPE idx_type= get_index_type_from_table(index_no);
2507  m_index[index_no].type= idx_type;
2508  DBUG_ENTER("ha_ndbcluster::add_index_handle");
2509  DBUG_PRINT("enter", ("table %s", m_tabname));
2510 
2511  ndb_protect_char(key_name, index_name, sizeof(index_name) - 1, '/');
2512  if (idx_type != PRIMARY_KEY_INDEX && idx_type != UNIQUE_INDEX)
2513  {
2514  DBUG_PRINT("info", ("Get handle to index %s", index_name));
2515  const NDBINDEX *index;
2516  do
2517  {
2518  index= dict->getIndexGlobal(index_name, *m_table);
2519  if (!index)
2520  ERR_RETURN(dict->getNdbError());
2521  DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d",
2522  (long) index,
2523  index->getObjectId(),
2524  index->getObjectVersion() & 0xFFFFFF,
2525  index->getObjectVersion() >> 24,
2526  index->getObjectStatus()));
2527  DBUG_ASSERT(index->getObjectStatus() ==
2529  break;
2530  } while (1);
2531  m_index[index_no].index= index;
2532  }
2533  if (idx_type == UNIQUE_ORDERED_INDEX || idx_type == UNIQUE_INDEX)
2534  {
2535  char unique_index_name[FN_LEN + 1];
2536  static const char* unique_suffix= "$unique";
2537  m_has_unique_index= TRUE;
2538  strxnmov(unique_index_name, FN_LEN, index_name, unique_suffix, NullS);
2539  DBUG_PRINT("info", ("Get handle to unique_index %s", unique_index_name));
2540  const NDBINDEX *index;
2541  do
2542  {
2543  index= dict->getIndexGlobal(unique_index_name, *m_table);
2544  if (!index)
2545  ERR_RETURN(dict->getNdbError());
2546  DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d",
2547  (long) index,
2548  index->getObjectId(),
2549  index->getObjectVersion() & 0xFFFFFF,
2550  index->getObjectVersion() >> 24,
2551  index->getObjectStatus()));
2552  DBUG_ASSERT(index->getObjectStatus() ==
2554  break;
2555  } while (1);
2556  m_index[index_no].unique_index= index;
2557  error= fix_unique_index_attr_order(m_index[index_no], index, key_info);
2558  }
2559 
2560  if (!error)
2561  error= add_index_ndb_record(dict, key_info, index_no);
2562 
2563  if (!error)
2564  m_index[index_no].status= ACTIVE;
2565 
2566  DBUG_RETURN(error);
2567 }
2568 
2569 /*
2570  We use this function to convert null bit masks, as found in class Field,
2571  to bit numbers, as used in NdbRecord.
2572 */
2573 static uint
2574 null_bit_mask_to_bit_number(uchar bit_mask)
2575 {
2576  switch (bit_mask)
2577  {
2578  case 0x1: return 0;
2579  case 0x2: return 1;
2580  case 0x4: return 2;
2581  case 0x8: return 3;
2582  case 0x10: return 4;
2583  case 0x20: return 5;
2584  case 0x40: return 6;
2585  case 0x80: return 7;
2586  default:
2587  DBUG_ASSERT(false);
2588  return 0;
2589  }
2590 }
2591 
2592 static void
2593 ndb_set_record_specification(uint field_no,
2595  const TABLE *table,
2596  const NdbDictionary::Table *ndb_table)
2597 {
2598  spec->column= ndb_table->getColumn(field_no);
2599  spec->offset= Uint32(table->field[field_no]->ptr - table->record[0]);
2600  if (table->field[field_no]->null_ptr)
2601  {
2602  spec->nullbit_byte_offset=
2603  Uint32(table->field[field_no]->null_ptr - table->record[0]);
2604  spec->nullbit_bit_in_byte=
2605  null_bit_mask_to_bit_number(table->field[field_no]->null_bit);
2606  }
2607  else if (table->field[field_no]->type() == MYSQL_TYPE_BIT)
2608  {
2609  /* We need to store the position of the overflow bits. */
2610  const Field_bit* field_bit= static_cast<Field_bit*>(table->field[field_no]);
2611  spec->nullbit_byte_offset=
2612  Uint32(field_bit->bit_ptr - table->record[0]);
2613  spec->nullbit_bit_in_byte= field_bit->bit_ofs;
2614  }
2615  else
2616  {
2617  spec->nullbit_byte_offset= 0;
2618  spec->nullbit_bit_in_byte= 0;
2619  }
2620 }
2621 
2622 int
2623 ha_ndbcluster::add_table_ndb_record(NDBDICT *dict)
2624 {
2625  DBUG_ENTER("ha_ndbcluster::add_table_ndb_record()");
2626  NdbDictionary::RecordSpecification spec[NDB_MAX_ATTRIBUTES_IN_TABLE + 2];
2627  NdbRecord *rec;
2628  uint i;
2629 
2630  for (i= 0; i < table_share->fields; i++)
2631  {
2632  ndb_set_record_specification(i, &spec[i], table, m_table);
2633  }
2634 
2635  rec= dict->createRecord(m_table, spec, i, sizeof(spec[0]),
2636  NdbDictionary::RecMysqldBitfield);
2637  if (! rec)
2638  ERR_RETURN(dict->getNdbError());
2639  m_ndb_record= rec;
2640 
2641  DBUG_RETURN(0);
2642 }
2643 
2644 /* Create NdbRecord for setting hidden primary key from Uint64. */
2645 int
2646 ha_ndbcluster::add_hidden_pk_ndb_record(NDBDICT *dict)
2647 {
2648  DBUG_ENTER("ha_ndbcluster::add_hidden_pk_ndb_record");
2650  NdbRecord *rec;
2651 
2652  spec[0].column= m_table->getColumn(table_share->fields);
2653  spec[0].offset= 0;
2654  spec[0].nullbit_byte_offset= 0;
2655  spec[0].nullbit_bit_in_byte= 0;
2656 
2657  rec= dict->createRecord(m_table, spec, 1, sizeof(spec[0]));
2658  if (! rec)
2659  ERR_RETURN(dict->getNdbError());
2660  m_ndb_hidden_key_record= rec;
2661 
2662  DBUG_RETURN(0);
2663 }
2664 
2665 int
2666 ha_ndbcluster::add_index_ndb_record(NDBDICT *dict, KEY *key_info, uint index_no)
2667 {
2668  DBUG_ENTER("ha_ndbcluster::add_index_ndb_record");
2669  NdbDictionary::RecordSpecification spec[NDB_MAX_ATTRIBUTES_IN_TABLE + 2];
2670  NdbRecord *rec;
2671 
2672  Uint32 offset= 0;
2673  for (uint i= 0; i < key_info->user_defined_key_parts; i++)
2674  {
2675  KEY_PART_INFO *kp= &key_info->key_part[i];
2676 
2677  spec[i].column= m_table->getColumn(kp->fieldnr - 1);
2678  if (! spec[i].column)
2679  ERR_RETURN(dict->getNdbError());
2680  if (kp->null_bit)
2681  {
2682  /* Nullable column. */
2683  spec[i].offset= offset + 1; // First byte is NULL flag
2684  spec[i].nullbit_byte_offset= offset;
2685  spec[i].nullbit_bit_in_byte= 0;
2686  }
2687  else
2688  {
2689  /* Not nullable column. */
2690  spec[i].offset= offset;
2691  spec[i].nullbit_byte_offset= 0;
2692  spec[i].nullbit_bit_in_byte= 0;
2693  }
2694  offset+= kp->store_length;
2695  }
2696 
2697  if (m_index[index_no].index)
2698  {
2699  /*
2700  Enable MysqldShrinkVarchar flag so that the two-byte length used by
2701  mysqld for short varchar keys is correctly converted into a one-byte
2702  length used by Ndb kernel.
2703  */
2704  rec= dict->createRecord(m_index[index_no].index, m_table,
2705  spec, key_info->user_defined_key_parts, sizeof(spec[0]),
2706  ( NdbDictionary::RecMysqldShrinkVarchar |
2707  NdbDictionary::RecMysqldBitfield ));
2708  if (! rec)
2709  ERR_RETURN(dict->getNdbError());
2710  m_index[index_no].ndb_record_key= rec;
2711  }
2712  else
2713  m_index[index_no].ndb_record_key= NULL;
2714 
2715  if (m_index[index_no].unique_index)
2716  {
2717  rec= dict->createRecord(m_index[index_no].unique_index, m_table,
2718  spec, key_info->user_defined_key_parts, sizeof(spec[0]),
2719  ( NdbDictionary::RecMysqldShrinkVarchar |
2720  NdbDictionary::RecMysqldBitfield ));
2721  if (! rec)
2722  ERR_RETURN(dict->getNdbError());
2723  m_index[index_no].ndb_unique_record_key= rec;
2724  }
2725  else if (index_no == table_share->primary_key)
2726  {
2727  /* The primary key is special, there is no explicit NDB index associated. */
2728  rec= dict->createRecord(m_table,
2729  spec, key_info->user_defined_key_parts, sizeof(spec[0]),
2730  ( NdbDictionary::RecMysqldShrinkVarchar |
2731  NdbDictionary::RecMysqldBitfield ));
2732  if (! rec)
2733  ERR_RETURN(dict->getNdbError());
2734  m_index[index_no].ndb_unique_record_key= rec;
2735  }
2736  else
2737  m_index[index_no].ndb_unique_record_key= NULL;
2738 
2739  /* Now do the same, but this time with offsets from Field, for row access. */
2740  for (uint i= 0; i < key_info->user_defined_key_parts; i++)
2741  {
2742  const KEY_PART_INFO *kp= &key_info->key_part[i];
2743 
2744  spec[i].offset= kp->offset;
2745  if (kp->null_bit)
2746  {
2747  /* Nullable column. */
2748  spec[i].nullbit_byte_offset= kp->null_offset;
2749  spec[i].nullbit_bit_in_byte= null_bit_mask_to_bit_number(kp->null_bit);
2750  }
2751  else
2752  {
2753  /* Not nullable column. */
2754  spec[i].nullbit_byte_offset= 0;
2755  spec[i].nullbit_bit_in_byte= 0;
2756  }
2757  }
2758 
2759  if (m_index[index_no].unique_index)
2760  {
2761  rec= dict->createRecord(m_index[index_no].unique_index, m_table,
2762  spec, key_info->user_defined_key_parts, sizeof(spec[0]),
2763  NdbDictionary::RecMysqldBitfield);
2764  if (! rec)
2765  ERR_RETURN(dict->getNdbError());
2766  m_index[index_no].ndb_unique_record_row= rec;
2767  }
2768  else if (index_no == table_share->primary_key)
2769  {
2770  rec= dict->createRecord(m_table,
2771  spec, key_info->user_defined_key_parts, sizeof(spec[0]),
2772  NdbDictionary::RecMysqldBitfield);
2773  if (! rec)
2774  ERR_RETURN(dict->getNdbError());
2775  m_index[index_no].ndb_unique_record_row= rec;
2776  }
2777  else
2778  m_index[index_no].ndb_unique_record_row= NULL;
2779 
2780  DBUG_RETURN(0);
2781 }
2782 
2783 /*
2784  Associate index handles for each index of a table
2785 */
2786 int ha_ndbcluster::open_indexes(THD *thd, Ndb *ndb, TABLE *tab,
2787  bool ignore_error)
2788 {
2789  uint i;
2790  int error= 0;
2791  NDBDICT *dict= ndb->getDictionary();
2792  KEY* key_info= tab->key_info;
2793  const char **key_name= tab->s->keynames.type_names;
2794  DBUG_ENTER("ha_ndbcluster::open_indexes");
2795  m_has_unique_index= FALSE;
2796  btree_keys.clear_all();
2797  for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
2798  {
2799  if ((error= add_index_handle(thd, dict, key_info, *key_name, i)))
2800  {
2801  if (ignore_error)
2802  m_index[i].index= m_index[i].unique_index= NULL;
2803  else
2804  break;
2805  }
2806  m_index[i].null_in_unique_index= FALSE;
2807  if (check_index_fields_not_null(key_info))
2808  m_index[i].null_in_unique_index= TRUE;
2809 
2810  if (error == 0 && test(index_flags(i, 0, 0) & HA_READ_RANGE))
2811  btree_keys.set_bit(i);
2812  }
2813 
2814  if (error && !ignore_error)
2815  {
2816  while (i > 0)
2817  {
2818  i--;
2819  if (m_index[i].index)
2820  {
2821  dict->removeIndexGlobal(*m_index[i].index, 1);
2822  m_index[i].index= NULL;
2823  }
2824  if (m_index[i].unique_index)
2825  {
2826  dict->removeIndexGlobal(*m_index[i].unique_index, 1);
2827  m_index[i].unique_index= NULL;
2828  }
2829  }
2830  }
2831 
2832  DBUG_ASSERT(error == 0 || error == 4243);
2833 
2834  DBUG_RETURN(error);
2835 }
2836 
2837 /*
2838  Renumber indexes in index list by shifting out
2839  indexes that are to be dropped
2840  */
2841 void ha_ndbcluster::renumber_indexes(Ndb *ndb, TABLE *tab)
2842 {
2843  uint i;
2844  const char *index_name;
2845  KEY* key_info= tab->key_info;
2846  const char **key_name= tab->s->keynames.type_names;
2847  DBUG_ENTER("ha_ndbcluster::renumber_indexes");
2848 
2849  for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
2850  {
2851  index_name= *key_name;
2852  NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
2853  m_index[i].type= idx_type;
2854  if (m_index[i].status == TO_BE_DROPPED)
2855  {
2856  DBUG_PRINT("info", ("Shifting index %s(%i) out of the list",
2857  index_name, i));
2858  NDB_INDEX_DATA tmp;
2859  uint j= i + 1;
2860  // Shift index out of list
2861  while(j != MAX_KEY && m_index[j].status != UNDEFINED)
2862  {
2863  tmp= m_index[j - 1];
2864  m_index[j - 1]= m_index[j];
2865  m_index[j]= tmp;
2866  j++;
2867  }
2868  }
2869  }
2870 
2871  DBUG_VOID_RETURN;
2872 }
2873 
2874 /*
2875  Drop all indexes that are marked for deletion
2876 */
2877 int ha_ndbcluster::drop_indexes(Ndb *ndb, TABLE *tab)
2878 {
2879  uint i;
2880  int error= 0;
2881  const char *index_name;
2882  KEY* key_info= tab->key_info;
2883  NDBDICT *dict= ndb->getDictionary();
2884  DBUG_ENTER("ha_ndbcluster::drop_indexes");
2885 
2886  for (i= 0; i < tab->s->keys; i++, key_info++)
2887  {
2888  NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
2889  m_index[i].type= idx_type;
2890  if (m_index[i].status == TO_BE_DROPPED)
2891  {
2892  const NdbDictionary::Index *index= m_index[i].index;
2893  const NdbDictionary::Index *unique_index= m_index[i].unique_index;
2894 
2895  if (index)
2896  {
2897  index_name= index->getName();
2898  DBUG_PRINT("info", ("Dropping index %u: %s", i, index_name));
2899  // Drop ordered index from ndb
2900  error= dict->dropIndexGlobal(*index);
2901  if (!error)
2902  {
2903  dict->removeIndexGlobal(*index, 1);
2904  m_index[i].index= NULL;
2905  }
2906  }
2907  if (!error && unique_index)
2908  {
2909  index_name= unique_index->getName();
2910  DBUG_PRINT("info", ("Dropping unique index %u: %s", i, index_name));
2911  // Drop unique index from ndb
2912  error= dict->dropIndexGlobal(*unique_index);
2913  if (!error)
2914  {
2915  dict->removeIndexGlobal(*unique_index, 1);
2916  m_index[i].unique_index= NULL;
2917  }
2918  }
2919  if (error)
2920  DBUG_RETURN(error);
2921  ndb_clear_index(dict, m_index[i]);
2922  continue;
2923  }
2924  }
2925 
2926  DBUG_RETURN(error);
2927 }
2928 
2933 NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_table(uint inx) const
2934 {
2935  return get_index_type_from_key(inx, table_share->key_info,
2936  inx == table_share->primary_key);
2937 }
2938 
2939 NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_key(uint inx,
2940  KEY *key_info,
2941  bool primary) const
2942 {
2943  bool is_hash_index= (key_info[inx].algorithm ==
2944  HA_KEY_ALG_HASH);
2945  if (primary)
2946  return is_hash_index ? PRIMARY_KEY_INDEX : PRIMARY_KEY_ORDERED_INDEX;
2947 
2948  return ((key_info[inx].flags & HA_NOSAME) ?
2949  (is_hash_index ? UNIQUE_INDEX : UNIQUE_ORDERED_INDEX) :
2950  ORDERED_INDEX);
2951 }
2952 
2953 bool ha_ndbcluster::check_index_fields_not_null(KEY* key_info)
2954 {
2955  KEY_PART_INFO* key_part= key_info->key_part;
2956  KEY_PART_INFO* end= key_part+key_info->user_defined_key_parts;
2957  DBUG_ENTER("ha_ndbcluster::check_index_fields_not_null");
2958 
2959  for (; key_part != end; key_part++)
2960  {
2961  Field* field= key_part->field;
2962  if (field->maybe_null())
2963  DBUG_RETURN(TRUE);
2964  }
2965 
2966  DBUG_RETURN(FALSE);
2967 }
2968 
2969 void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb)
2970 {
2971  uint i;
2972 
2973  DBUG_ENTER("release_metadata");
2974  DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
2975 
2976  NDBDICT *dict= ndb->getDictionary();
2977  int invalidate_indexes= 0;
2978  if (thd && thd->lex && thd->lex->sql_command == SQLCOM_FLUSH)
2979  {
2980  invalidate_indexes = 1;
2981  }
2982  if (m_table != NULL)
2983  {
2984  if (m_ndb_record != NULL)
2985  {
2986  dict->releaseRecord(m_ndb_record);
2987  m_ndb_record= NULL;
2988  }
2989  if (m_ndb_hidden_key_record != NULL)
2990  {
2991  dict->releaseRecord(m_ndb_hidden_key_record);
2992  m_ndb_hidden_key_record= NULL;
2993  }
2995  invalidate_indexes= 1;
2996  dict->removeTableGlobal(*m_table, invalidate_indexes);
2997  }
2998  // TODO investigate
2999  DBUG_ASSERT(m_table_info == NULL);
3000  m_table_info= NULL;
3001 
3002  // Release index list
3003  for (i= 0; i < MAX_KEY; i++)
3004  {
3005  if (m_index[i].unique_index)
3006  {
3007  DBUG_ASSERT(m_table != NULL);
3008  dict->removeIndexGlobal(*m_index[i].unique_index, invalidate_indexes);
3009  }
3010  if (m_index[i].index)
3011  {
3012  DBUG_ASSERT(m_table != NULL);
3013  dict->removeIndexGlobal(*m_index[i].index, invalidate_indexes);
3014  }
3015  ndb_clear_index(dict, m_index[i]);
3016  }
3017 
3018  m_table= NULL;
3019  DBUG_VOID_RETURN;
3020 }
3021 
3022 
3023 /*
3024  Map from thr_lock_type to NdbOperation::LockMode
3025 */
3026 static inline
3027 NdbOperation::LockMode get_ndb_lock_mode(enum thr_lock_type type)
3028 {
3029  if (type >= TL_WRITE_ALLOW_WRITE)
3031  if (type == TL_READ_WITH_SHARED_LOCKS)
3032  return NdbOperation::LM_Read;
3034 }
3035 
3036 
3037 static const ulong index_type_flags[]=
3038 {
3039  /* UNDEFINED_INDEX */
3040  0,
3041 
3042  /* PRIMARY_KEY_INDEX */
3043  HA_ONLY_WHOLE_INDEX,
3044 
3045  /* PRIMARY_KEY_ORDERED_INDEX */
3046  /*
3047  Enable HA_KEYREAD_ONLY when "sorted" indexes are supported,
3048  thus ORDER BY clauses can be optimized by reading directly
3049  through the index.
3050  */
3051  // HA_KEYREAD_ONLY |
3052  HA_READ_NEXT |
3053  HA_READ_PREV |
3054  HA_READ_RANGE |
3055  HA_READ_ORDER,
3056 
3057  /* UNIQUE_INDEX */
3058  HA_ONLY_WHOLE_INDEX,
3059 
3060  /* UNIQUE_ORDERED_INDEX */
3061  HA_READ_NEXT |
3062  HA_READ_PREV |
3063  HA_READ_RANGE |
3064  HA_READ_ORDER,
3065 
3066  /* ORDERED_INDEX */
3067  HA_READ_NEXT |
3068  HA_READ_PREV |
3069  HA_READ_RANGE |
3070  HA_READ_ORDER
3071 };
3072 
3073 static const int index_flags_size= sizeof(index_type_flags)/sizeof(ulong);
3074 
3075 inline NDB_INDEX_TYPE ha_ndbcluster::get_index_type(uint idx_no) const
3076 {
3077  DBUG_ASSERT(idx_no < MAX_KEY);
3078  return m_index[idx_no].type;
3079 }
3080 
3081 inline bool ha_ndbcluster::has_null_in_unique_index(uint idx_no) const
3082 {
3083  DBUG_ASSERT(idx_no < MAX_KEY);
3084  return m_index[idx_no].null_in_unique_index;
3085 }
3086 
3087 
3095 inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part,
3096  bool all_parts) const
3097 {
3098  DBUG_ENTER("ha_ndbcluster::index_flags");
3099  DBUG_PRINT("enter", ("idx_no: %u", idx_no));
3100  DBUG_ASSERT(get_index_type_from_table(idx_no) < index_flags_size);
3101  DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)] |
3102  HA_KEY_SCAN_NOT_ROR);
3103 }
3104 
3105 bool
3106 ha_ndbcluster::primary_key_is_clustered()
3107 {
3108 
3109  if (table->s->primary_key == MAX_KEY)
3110  return false;
3111 
3112  /*
3113  NOTE 1: our ordered indexes are not really clustered
3114  but since accesing data when scanning index is free
3115  it's a good approximation
3116 
3117  NOTE 2: We really should consider DD attributes here too
3118  (for which there is IO to read data when scanning index)
3119  but that will need to be handled later...
3120  */
3121  const ndb_index_type idx_type =
3122  get_index_type_from_table(table->s->primary_key);
3123  return (idx_type == PRIMARY_KEY_ORDERED_INDEX ||
3124  idx_type == UNIQUE_ORDERED_INDEX ||
3125  idx_type == ORDERED_INDEX);
3126 }
3127 
3128 bool ha_ndbcluster::check_index_fields_in_write_set(uint keyno)
3129 {
3130  KEY* key_info= table->key_info + keyno;
3131  KEY_PART_INFO* key_part= key_info->key_part;
3132  KEY_PART_INFO* end= key_part+key_info->user_defined_key_parts;
3133  uint i;
3134  DBUG_ENTER("check_index_fields_in_write_set");
3135 
3136  for (i= 0; key_part != end; key_part++, i++)
3137  {
3138  Field* field= key_part->field;
3139  if (!bitmap_is_set(table->write_set, field->field_index))
3140  {
3141  DBUG_RETURN(false);
3142  }
3143  }
3144 
3145  DBUG_RETURN(true);
3146 }
3147 
3148 
3153 int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf,
3154  uint32 *part_id)
3155 {
3156  NdbConnection *trans= m_thd_ndb->trans;
3157  int res;
3158  DBUG_ENTER("pk_read");
3159  DBUG_PRINT("enter", ("key_len: %u read_set=%x",
3160  key_len, table->read_set->bitmap[0]));
3161  DBUG_DUMP("key", key, key_len);
3162  DBUG_ASSERT(trans);
3163 
3164  NdbOperation::LockMode lm= get_ndb_lock_mode(m_lock.type);
3165 
3166 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
3167  if (check_if_pushable(NdbQueryOperationDef::PrimaryKeyAccess, table->s->primary_key))
3168  {
3169  // Is parent of pushed join
3170  DBUG_ASSERT(lm == NdbOperation::LM_CommittedRead);
3171  const int error= pk_unique_index_read_key_pushed(table->s->primary_key, key,
3172  (m_user_defined_partitioning ?
3173  part_id : NULL));
3174  if (unlikely(error))
3175  DBUG_RETURN(error);
3176 
3177  DBUG_ASSERT(m_active_query!=NULL);
3178  if ((res = execute_no_commit_ie(m_thd_ndb, trans)) != 0 ||
3179  m_active_query->getNdbError().code)
3180  {
3181  table->status= STATUS_NOT_FOUND;
3182  DBUG_RETURN(ndb_err(trans));
3183  }
3184 
3185  int result= fetch_next_pushed();
3186  if (result == NdbQuery::NextResult_gotRow)
3187  {
3188  DBUG_RETURN(0);
3189  }
3190  else if (result == NdbQuery::NextResult_scanComplete)
3191  {
3192  DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
3193  }
3194  else
3195  {
3196  DBUG_RETURN(ndb_err(trans));
3197  }
3198  }
3199  else
3200 #endif
3201  {
3202  if (m_pushed_join_operation == PUSHED_ROOT)
3203  {
3204  m_thd_ndb->m_pushed_queries_dropped++;
3205  }
3206 
3207  const NdbOperation *op;
3208  if (!(op= pk_unique_index_read_key(table->s->primary_key, key, buf, lm,
3209  (m_user_defined_partitioning ?
3210  part_id :
3211  NULL))))
3212  ERR_RETURN(trans->getNdbError());
3213 
3214  if ((res = execute_no_commit_ie(m_thd_ndb, trans)) != 0 ||
3215  op->getNdbError().code)
3216  {
3217  table->status= STATUS_NOT_FOUND;
3218  DBUG_RETURN(ndb_err(trans));
3219  }
3220  table->status= 0;
3221  DBUG_RETURN(0);
3222  }
3223 }
3224 
3229 int ha_ndbcluster::ndb_pk_update_row(THD *thd,
3230  const uchar *old_data, uchar *new_data,
3231  uint32 old_part_id)
3232 {
3233  NdbTransaction *trans= m_thd_ndb->trans;
3234  int error;
3235  const NdbOperation *op;
3236  DBUG_ENTER("ndb_pk_update_row");
3237  DBUG_ASSERT(trans);
3238 
3239  NdbOperation::OperationOptions *poptions = NULL;
3241  options.optionsPresent=0;
3242 
3243  DBUG_PRINT("info", ("primary key update or partition change, "
3244  "doing read+delete+insert"));
3245  // Get all old fields, since we optimize away fields not in query
3246 
3247  const NdbRecord *key_rec;
3248  const uchar *key_row;
3249 
3250  if (m_user_defined_partitioning)
3251  {
3252  options.optionsPresent |= NdbOperation::OperationOptions::OO_PARTITION_ID;
3253  options.partitionId=old_part_id;
3254  poptions=&options;
3255  }
3256 
3257  setup_key_ref_for_ndb_record(&key_rec, &key_row, old_data, FALSE);
3258 
3259  if (!bitmap_is_set_all(table->read_set))
3260  {
3261  /*
3262  Need to read rest of columns for later re-insert.
3263 
3264  Use mask only with columns that are not in write_set, not in
3265  read_set, and not part of the primary key.
3266  */
3267 
3268  bitmap_copy(&m_bitmap, table->read_set);
3269  bitmap_union(&m_bitmap, table->write_set);
3270  bitmap_invert(&m_bitmap);
3271  if (!(op= trans->readTuple(key_rec, (const char *)key_row,
3272  m_ndb_record, (char *)new_data,
3273  get_ndb_lock_mode(m_lock.type),
3274  (const unsigned char *)(m_bitmap.bitmap),
3275  poptions,
3277  ERR_RETURN(trans->getNdbError());
3278 
3279  if (table_share->blob_fields > 0)
3280  {
3281  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
3282  error= get_blob_values(op, new_data, &m_bitmap);
3283  dbug_tmp_restore_column_map(table->read_set, old_map);
3284  if (error != 0)
3285  ERR_RETURN(op->getNdbError());
3286  }
3287  if (execute_no_commit(m_thd_ndb, trans, m_ignore_no_key) != 0)
3288  {
3289  table->status= STATUS_NOT_FOUND;
3290  DBUG_RETURN(ndb_err(trans));
3291  }
3292  }
3293 
3294  // Delete old row
3295  error= ndb_delete_row(old_data, TRUE);
3296  if (error)
3297  {
3298  DBUG_PRINT("info", ("delete failed"));
3299  DBUG_RETURN(error);
3300  }
3301 
3302  // Insert new row
3303  DBUG_PRINT("info", ("delete succeded"));
3304  bool batched_update= (m_active_cursor != 0);
3305  /*
3306  If we are updating a primary key with auto_increment
3307  then we need to update the auto_increment counter
3308  */
3309  if (table->found_next_number_field &&
3310  bitmap_is_set(table->write_set,
3311  table->found_next_number_field->field_index) &&
3312  (error= set_auto_inc(thd, table->found_next_number_field)))
3313  {
3314  DBUG_RETURN(error);
3315  }
3316 
3317  /*
3318  We are mapping a MySQLD PK changing update to an NdbApi delete
3319  and insert.
3320  The original PK changing update may not have written new values
3321  to all columns, so the write set may be partial.
3322  We set the write set to be all columns so that all values are
3323  copied from the old row to the new row.
3324  */
3325  my_bitmap_map *old_map=
3326  tmp_use_all_columns(table, table->write_set);
3327  error= ndb_write_row(new_data, TRUE, batched_update);
3328  tmp_restore_column_map(table->write_set, old_map);
3329 
3330  if (error)
3331  {
3332  DBUG_PRINT("info", ("insert failed"));
3333  if (trans->commitStatus() == NdbConnection::Started)
3334  {
3335  if (thd->slave_thread)
3336  g_ndb_slave_state.atTransactionAbort();
3337  m_thd_ndb->m_unsent_bytes= 0;
3338  m_thd_ndb->m_execute_count++;
3339  DBUG_PRINT("info", ("execute_count: %u", m_thd_ndb->m_execute_count));
3341 #ifdef FIXED_OLD_DATA_TO_ACTUALLY_CONTAIN_GOOD_DATA
3342  int undo_res;
3343  // Undo delete_row(old_data)
3344  undo_res= ndb_write_row((uchar *)old_data, TRUE, batched_update);
3345  if (undo_res)
3346  push_warning(table->in_use,
3347  Sql_condition::WARN_LEVEL_WARN,
3348  undo_res,
3349  "NDB failed undoing delete at primary key update");
3350 #endif
3351  }
3352  DBUG_RETURN(error);
3353  }
3354  DBUG_PRINT("info", ("delete+insert succeeded"));
3355 
3356  DBUG_RETURN(0);
3357 }
3358 
3365 bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
3366  const NdbOperation *first,
3367  const NdbOperation *last,
3368  uint errcode)
3369 {
3370  const NdbOperation *op= first;
3371  DBUG_ENTER("ha_ndbcluster::check_all_operations_for_error");
3372 
3373  while(op)
3374  {
3375  NdbError err= op->getNdbError();
3376  if (err.status != NdbError::Success)
3377  {
3378  if (ndb_to_mysql_error(&err) != (int) errcode)
3379  DBUG_RETURN(FALSE);
3380  if (op == last) break;
3381  op= trans->getNextCompletedOperation(op);
3382  }
3383  else
3384  {
3385  // We found a duplicate
3387  {
3388  if (errcode == HA_ERR_KEY_NOT_FOUND)
3389  {
3390  NdbIndexOperation *iop= (NdbIndexOperation *) op;
3391  const NDBINDEX *index= iop->getIndex();
3392  // Find the key_no of the index
3393  for(uint i= 0; i<table->s->keys; i++)
3394  {
3395  if (m_index[i].unique_index == index)
3396  {
3397  m_dupkey= i;
3398  break;
3399  }
3400  }
3401  }
3402  }
3403  else
3404  {
3405  // Must have been primary key access
3406  DBUG_ASSERT(op->getType() == NdbOperation::PrimaryKeyAccess);
3407  if (errcode == HA_ERR_KEY_NOT_FOUND)
3408  m_dupkey= table->s->primary_key;
3409  }
3410  DBUG_RETURN(FALSE);
3411  }
3412  }
3413  DBUG_RETURN(TRUE);
3414 }
3415 
3416 
3420 static
3421 int
3422 check_null_in_record(const KEY* key_info, const uchar *record)
3423 {
3424  KEY_PART_INFO *curr_part, *end_part;
3425  curr_part= key_info->key_part;
3426  end_part= curr_part + key_info->user_defined_key_parts;
3427 
3428  while (curr_part != end_part)
3429  {
3430  if (curr_part->null_bit &&
3431  (record[curr_part->null_offset] & curr_part->null_bit))
3432  return 1;
3433  curr_part++;
3434  }
3435  return 0;
3436  /*
3437  We could instead pre-compute a bitmask in table_share with one bit for
3438  every null-bit in the key, and so check this just by OR'ing the bitmask
3439  with the null bitmap in the record.
3440  But not sure it's worth it.
3441  */
3442 }
3443 
3444 /* Empty mask and dummy row, for reading no attributes using NdbRecord. */
3445 /* Mask will be initialized to all zeros by linker. */
3446 static unsigned char empty_mask[(NDB_MAX_ATTRIBUTES_IN_TABLE+7)/8];
3447 static char dummy_row[1];
3448 
3454 int ha_ndbcluster::peek_indexed_rows(const uchar *record,
3455  NDB_WRITE_OP write_op)
3456 {
3457  NdbTransaction *trans;
3458  const NdbOperation *op;
3459  const NdbOperation *first, *last;
3461  NdbOperation::OperationOptions *poptions=NULL;
3462  options.optionsPresent = 0;
3463  uint i;
3464  int res, error;
3465  DBUG_ENTER("peek_indexed_rows");
3466  if (unlikely(!(trans= get_transaction(error))))
3467  {
3468  DBUG_RETURN(error);
3469  }
3470  const NdbOperation::LockMode lm = get_ndb_lock_mode(m_lock.type);
3471  first= NULL;
3472  if (write_op != NDB_UPDATE && table->s->primary_key != MAX_KEY)
3473  {
3474  /*
3475  * Fetch any row with colliding primary key
3476  */
3477  const NdbRecord *key_rec=
3478  m_index[table->s->primary_key].ndb_unique_record_row;
3479 
3480  if (m_user_defined_partitioning)
3481  {
3482  uint32 part_id;
3483  int error;
3484  longlong func_value;
3485  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
3486  error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
3487  dbug_tmp_restore_column_map(table->read_set, old_map);
3488  if (error)
3489  {
3490  m_part_info->err_value= func_value;
3491  DBUG_RETURN(error);
3492  }
3493  options.optionsPresent |= NdbOperation::OperationOptions::OO_PARTITION_ID;
3494  options.partitionId=part_id;
3495  poptions=&options;
3496  }
3497 
3498  if (!(op= trans->readTuple(key_rec, (const char *)record,
3499  m_ndb_record, dummy_row, lm, empty_mask,
3500  poptions,
3502  ERR_RETURN(trans->getNdbError());
3503 
3504  first= op;
3505  }
3506  /*
3507  * Fetch any rows with colliding unique indexes
3508  */
3509  KEY* key_info;
3510  for (i= 0, key_info= table->key_info; i < table->s->keys; i++, key_info++)
3511  {
3512  if (i != table_share->primary_key &&
3513  key_info->flags & HA_NOSAME &&
3514  bitmap_is_overlapping(table->write_set, m_key_fields[i]))
3515  {
3516  /*
3517  A unique index is defined on table and it's being updated
3518  We cannot look up a NULL field value in a unique index. But since
3519  keys with NULLs are not indexed, such rows cannot conflict anyway, so
3520  we just skip the index in this case.
3521  */
3522  if (check_null_in_record(key_info, record))
3523  {
3524  DBUG_PRINT("info", ("skipping check for key with NULL"));
3525  continue;
3526  }
3527  if (write_op != NDB_INSERT && !check_index_fields_in_write_set(i))
3528  {
3529  DBUG_PRINT("info", ("skipping check for key %u not in write_set", i));
3530  continue;
3531  }
3532 
3533  const NdbOperation *iop;
3534  const NdbRecord *key_rec= m_index[i].ndb_unique_record_row;
3535  if (!(iop= trans->readTuple(key_rec, (const char *)record,
3536  m_ndb_record, dummy_row,
3537  lm, empty_mask)))
3538  ERR_RETURN(trans->getNdbError());
3539 
3540  if (!first)
3541  first= iop;
3542  }
3543  }
3544  last= trans->getLastDefinedOperation();
3545  if (first)
3546  res= execute_no_commit_ie(m_thd_ndb, trans);
3547  else
3548  {
3549  // Table has no keys
3550  table->status= STATUS_NOT_FOUND;
3551  DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
3552  }
3553  if (check_all_operations_for_error(trans, first, last,
3554  HA_ERR_KEY_NOT_FOUND))
3555  {
3556  table->status= STATUS_NOT_FOUND;
3557  DBUG_RETURN(ndb_err(trans));
3558  }
3559  else
3560  {
3561  DBUG_PRINT("info", ("m_dupkey %d", m_dupkey));
3562  }
3563  DBUG_RETURN(0);
3564 }
3565 
3566 
3571 int ha_ndbcluster::unique_index_read(const uchar *key,
3572  uint key_len, uchar *buf)
3573 {
3574  NdbTransaction *trans= m_thd_ndb->trans;
3575  DBUG_ENTER("ha_ndbcluster::unique_index_read");
3576  DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index));
3577  DBUG_DUMP("key", key, key_len);
3578  DBUG_ASSERT(trans);
3579 
3580  NdbOperation::LockMode lm= get_ndb_lock_mode(m_lock.type);
3581 
3582 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
3583  if (check_if_pushable(NdbQueryOperationDef::UniqueIndexAccess, active_index))
3584  {
3585  DBUG_ASSERT(lm == NdbOperation::LM_CommittedRead);
3586  const int error= pk_unique_index_read_key_pushed(active_index, key, NULL);
3587  if (unlikely(error))
3588  DBUG_RETURN(error);
3589 
3590  DBUG_ASSERT(m_active_query!=NULL);
3591  if (execute_no_commit_ie(m_thd_ndb, trans) != 0 ||
3592  m_active_query->getNdbError().code)
3593  {
3594  table->status= STATUS_GARBAGE;
3595  DBUG_RETURN(ndb_err(trans));
3596  }
3597 
3598  int result= fetch_next_pushed();
3599  if (result == NdbQuery::NextResult_gotRow)
3600  {
3601  DBUG_RETURN(0);
3602  }
3603  else if (result == NdbQuery::NextResult_scanComplete)
3604  {
3605  DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
3606  }
3607  else
3608  {
3609  DBUG_RETURN(ndb_err(trans));
3610  }
3611  }
3612  else
3613 #endif
3614  {
3615  if (m_pushed_join_operation == PUSHED_ROOT)
3616  {
3617  m_thd_ndb->m_pushed_queries_dropped++;
3618  }
3619 
3620  const NdbOperation *op;
3621 
3622  if (!(op= pk_unique_index_read_key(active_index, key, buf, lm, NULL)))
3623  ERR_RETURN(trans->getNdbError());
3624 
3625  if (execute_no_commit_ie(m_thd_ndb, trans) != 0 ||
3626  op->getNdbError().code)
3627  {
3628  int err= ndb_err(trans);
3629  if(err==HA_ERR_KEY_NOT_FOUND)
3630  table->status= STATUS_NOT_FOUND;
3631  else
3632  table->status= STATUS_GARBAGE;
3633 
3634  DBUG_RETURN(err);
3635  }
3636 
3637  table->status= 0;
3638  DBUG_RETURN(0);
3639  }
3640 }
3641 
3642 int
3643 ha_ndbcluster::scan_handle_lock_tuple(NdbScanOperation *scanOp,
3644  NdbTransaction *trans)
3645 {
3646  DBUG_ENTER("ha_ndbcluster::scan_handle_lock_tuple");
3647  if (m_lock_tuple)
3648  {
3649  /*
3650  Lock level m_lock.type either TL_WRITE_ALLOW_WRITE
3651  (SELECT FOR UPDATE) or TL_READ_WITH_SHARED_LOCKS (SELECT
3652  LOCK WITH SHARE MODE) and row was not explictly unlocked
3653  with unlock_row() call
3654  */
3655  const NdbOperation *op;
3656  // Lock row
3657  DBUG_PRINT("info", ("Keeping lock on scanned row"));
3658 
3659  if (!(op= scanOp->lockCurrentTuple(trans, m_ndb_record,
3660  dummy_row, empty_mask)))
3661  {
3662  /* purecov: begin inspected */
3663  m_lock_tuple= FALSE;
3664  ERR_RETURN(trans->getNdbError());
3665  /* purecov: end */
3666  }
3667  m_thd_ndb->m_unsent_bytes+=12;
3668  }
3669  m_lock_tuple= FALSE;
3670  DBUG_RETURN(0);
3671 }
3672 
3673 inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
3674 {
3675  DBUG_ENTER("fetch_next");
3676  int local_check;
3677  int error;
3678  NdbTransaction *trans= m_thd_ndb->trans;
3679 
3680  DBUG_ASSERT(trans);
3681  if ((error= scan_handle_lock_tuple(cursor, trans)) != 0)
3682  DBUG_RETURN(error);
3683 
3684  bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE &&
3685  m_lock.type != TL_READ_WITH_SHARED_LOCKS;
3686  do {
3687  DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb));
3688  /*
3689  We can only handle one tuple with blobs at a time.
3690  */
3691  if (m_thd_ndb->m_unsent_bytes && m_blobs_pending)
3692  {
3693  if (execute_no_commit(m_thd_ndb, trans, m_ignore_no_key) != 0)
3694  DBUG_RETURN(ndb_err(trans));
3695  }
3696 
3697  /* Should be no unexamined completed operations
3698  nextResult() on Blobs generates Blob part read ops,
3699  so we will free them here
3700  */
3701  release_completed_operations(trans);
3702 
3703  if ((local_check= cursor->nextResult(&_m_next_row,
3704  contact_ndb,
3705  m_thd_ndb->m_force_send)) == 0)
3706  {
3707  /*
3708  Explicitly lock tuple if "select for update" or
3709  "select lock in share mode"
3710  */
3711  m_lock_tuple= (m_lock.type == TL_WRITE_ALLOW_WRITE
3712  ||
3713  m_lock.type == TL_READ_WITH_SHARED_LOCKS);
3714  DBUG_RETURN(0);
3715  }
3716  else if (local_check == 1 || local_check == 2)
3717  {
3718  // 1: No more records
3719  // 2: No more cached records
3720 
3721  /*
3722  Before fetching more rows and releasing lock(s),
3723  all pending update or delete operations should
3724  be sent to NDB
3725  */
3726  DBUG_PRINT("info", ("thd_ndb->m_unsent_bytes: %ld",
3727  (long) m_thd_ndb->m_unsent_bytes));
3728  if (m_thd_ndb->m_unsent_bytes)
3729  {
3730  if ((error = flush_bulk_insert()) != 0)
3731  DBUG_RETURN(error);
3732  }
3733  contact_ndb= (local_check == 2);
3734  }
3735  else
3736  {
3737  DBUG_RETURN(ndb_err(trans));
3738  }
3739  } while (local_check == 2);
3740 
3741  DBUG_RETURN(1);
3742 }
3743 
3744 int ha_ndbcluster::fetch_next_pushed()
3745 {
3746  DBUG_ENTER("fetch_next_pushed (from pushed operation)");
3747 
3748  DBUG_ASSERT(m_pushed_operation);
3749  NdbQuery::NextResultOutcome result= m_pushed_operation->nextResult(true, m_thd_ndb->m_force_send);
3750 
3756  if (result == NdbQuery::NextResult_gotRow)
3757  {
3758  DBUG_ASSERT(m_next_row!=NULL);
3759  DBUG_PRINT("info", ("One more record found"));
3760  table->status= 0;
3761  unpack_record(table->record[0], m_next_row);
3762 // m_thd_ndb->m_pushed_reads++;
3763 // DBUG_RETURN(0)
3764  }
3765  else if (result == NdbQuery::NextResult_scanComplete)
3766  {
3767  DBUG_ASSERT(m_next_row==NULL);
3768  DBUG_PRINT("info", ("No more records"));
3769  table->status= STATUS_NOT_FOUND;
3770 // m_thd_ndb->m_pushed_reads++;
3771 // DBUG_RETURN(HA_ERR_END_OF_FILE);
3772  }
3773  else
3774  {
3775  DBUG_PRINT("info", ("Error from 'nextResult()'"));
3776  table->status= STATUS_GARBAGE;
3777 // DBUG_ASSERT(false);
3778 // DBUG_RETURN(ndb_err(m_thd_ndb->trans));
3779  }
3780  DBUG_RETURN(result);
3781 }
3782 
3790 int
3791 ha_ndbcluster::index_read_pushed(uchar *buf, const uchar *key,
3792  key_part_map keypart_map)
3793 {
3794  DBUG_ENTER("index_read_pushed");
3795 
3796  // Handler might have decided to not execute the pushed joins which has been prepared
3797  // In this case we do an unpushed index_read based on 'Plain old' NdbOperations
3798  if (unlikely(!check_is_pushed()))
3799  {
3800  DBUG_RETURN(index_read_map(buf, key, keypart_map, HA_READ_KEY_EXACT));
3801  }
3802 
3803  // Might need to re-establish first result row (wrt. its parents which may have been navigated)
3804  NdbQuery::NextResultOutcome result= m_pushed_operation->firstResult();
3805 
3806  // Result from pushed operation will be referred by 'm_next_row' if non-NULL
3807  if (result == NdbQuery::NextResult_gotRow)
3808  {
3809  DBUG_ASSERT(m_next_row!=NULL);
3810  unpack_record(buf, m_next_row);
3811  table->status= 0;
3812  m_thd_ndb->m_pushed_reads++;
3813  }
3814  else
3815  {
3816  DBUG_ASSERT(result!=NdbQuery::NextResult_gotRow);
3817  table->status= STATUS_NOT_FOUND;
3818  DBUG_PRINT("info", ("No record found"));
3819 // m_thd_ndb->m_pushed_reads++;
3820 // DBUG_RETURN(HA_ERR_END_OF_FILE);
3821  }
3822  DBUG_RETURN(0);
3823 }
3824 
3825 
3832 int ha_ndbcluster::index_next_pushed(uchar *buf)
3833 {
3834  DBUG_ENTER("index_next_pushed");
3835 
3836  // Handler might have decided to not execute the pushed joins which has been prepared
3837  // In this case we do an unpushed index_read based on 'Plain old' NdbOperations
3838  if (unlikely(!check_is_pushed()))
3839  {
3840  DBUG_RETURN(index_next(buf));
3841  }
3842 
3843  DBUG_ASSERT(m_pushed_join_operation>PUSHED_ROOT); // Child of a pushed join
3844  DBUG_ASSERT(m_active_query==NULL);
3845 
3846  int res = fetch_next_pushed();
3847  if (res == NdbQuery::NextResult_gotRow)
3848  {
3849  DBUG_RETURN(0);
3850  }
3851  else if (res == NdbQuery::NextResult_scanComplete)
3852  {
3853  DBUG_RETURN(HA_ERR_END_OF_FILE);
3854  }
3855  else
3856  {
3857  DBUG_RETURN(ndb_err(m_thd_ndb->trans));
3858  }
3859 }
3860 
3861 
3872 inline int ha_ndbcluster::next_result(uchar *buf)
3873 {
3874  int res;
3875  DBUG_ENTER("next_result");
3876 
3877  if (m_active_cursor)
3878  {
3879  if ((res= fetch_next(m_active_cursor)) == 0)
3880  {
3881  DBUG_PRINT("info", ("One more record found"));
3882 
3883  unpack_record(buf, m_next_row);
3884  table->status= 0;
3885  DBUG_RETURN(0);
3886  }
3887  else if (res == 1)
3888  {
3889  // No more records
3890  table->status= STATUS_NOT_FOUND;
3891 
3892  DBUG_PRINT("info", ("No more records"));
3893  DBUG_RETURN(HA_ERR_END_OF_FILE);
3894  }
3895  else
3896  {
3897  DBUG_RETURN(ndb_err(m_thd_ndb->trans));
3898  }
3899  }
3900  else if (m_active_query)
3901  {
3902  res= fetch_next_pushed();
3903  if (res == NdbQuery::NextResult_gotRow)
3904  {
3905  DBUG_RETURN(0);
3906  }
3907  else if (res == NdbQuery::NextResult_scanComplete)
3908  {
3909  DBUG_RETURN(HA_ERR_END_OF_FILE);
3910  }
3911  else
3912  {
3913  DBUG_RETURN(ndb_err(m_thd_ndb->trans));
3914  }
3915  }
3916  else
3917  DBUG_RETURN(HA_ERR_END_OF_FILE);
3918 }
3919 
3924 const NdbOperation *
3925 ha_ndbcluster::pk_unique_index_read_key(uint idx, const uchar *key, uchar *buf,
3927  Uint32 *ppartition_id)
3928 {
3929  const NdbOperation *op;
3930  const NdbRecord *key_rec;
3932  NdbOperation::OperationOptions *poptions = NULL;
3933  options.optionsPresent= 0;
3935 
3936  DBUG_ASSERT(m_thd_ndb->trans);
3937 
3938  if (idx != MAX_KEY)
3939  key_rec= m_index[idx].ndb_unique_record_key;
3940  else
3941  key_rec= m_ndb_hidden_key_record;
3942 
3943  /* Initialize the null bitmap, setting unused null bits to 1. */
3944  memset(buf, 0xff, table->s->null_bytes);
3945 
3946  if (table_share->primary_key == MAX_KEY)
3947  {
3948  get_hidden_fields_keyop(&options, gets);
3949  poptions= &options;
3950  }
3951 
3952  if (ppartition_id != NULL)
3953  {
3954  assert(m_user_defined_partitioning);
3955  options.optionsPresent|= NdbOperation::OperationOptions::OO_PARTITION_ID;
3956  options.partitionId= *ppartition_id;
3957  poptions= &options;
3958  }
3959 
3960  op= m_thd_ndb->trans->readTuple(key_rec, (const char *)key, m_ndb_record,
3961  (char *)buf, lm,
3962  (uchar *)(table->read_set->bitmap), poptions,
3964 
3965  if (uses_blob_value(table->read_set) &&
3966  get_blob_values(op, buf, table->read_set) != 0)
3967  return NULL;
3968 
3969  return op;
3970 }
3971 
3972 extern void sql_print_information(const char *format, ...);
3973 
3974 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
3975 static
3976 bool
3977 is_shrinked_varchar(const Field *field)
3978 {
3979  if (field->real_type() == MYSQL_TYPE_VARCHAR)
3980  {
3981  if (((Field_varstring*)field)->length_bytes == 1)
3982  return true;
3983  }
3984 
3985  return false;
3986 }
3987 
3988 int
3989 ha_ndbcluster::pk_unique_index_read_key_pushed(uint idx,
3990  const uchar *key,
3991  Uint32 *ppartition_id)
3992 {
3993  DBUG_ENTER("pk_unique_index_read_key_pushed");
3995  NdbOperation::OperationOptions *poptions = NULL;
3996  options.optionsPresent= 0;
3998 
3999  DBUG_ASSERT(m_thd_ndb->trans);
4000  DBUG_ASSERT(idx < MAX_KEY);
4001 
4002  if (m_active_query)
4003  {
4004  m_active_query->close(FALSE);
4005  m_active_query= NULL;
4006  }
4007 
4008  if (table_share->primary_key == MAX_KEY)
4009  {
4010  get_hidden_fields_keyop(&options, gets);
4011  poptions= &options;
4012  }
4013 
4014  if (ppartition_id != NULL)
4015  {
4016  assert(m_user_defined_partitioning);
4017  options.optionsPresent|= NdbOperation::OperationOptions::OO_PARTITION_ID;
4018  options.partitionId= *ppartition_id;
4019  poptions= &options;
4020  }
4021 
4022  KEY *key_def= &table->key_info[idx];
4023  KEY_PART_INFO *key_part;
4024 
4025  uint i;
4026  Uint32 offset= 0;
4028  DBUG_ASSERT(key_def->user_defined_key_parts <= ndb_pushed_join::MAX_KEY_PART);
4029 
4031  ndbcluster_build_key_map(m_table, m_index[idx], &table->key_info[idx], map);
4032 
4033  // Bind key values defining root of pushed join
4034  for (i = 0, key_part= key_def->key_part; i < key_def->user_defined_key_parts; i++, key_part++)
4035  {
4036  bool shrinkVarChar= is_shrinked_varchar(key_part->field);
4037 
4038  if (key_part->null_bit) // Column is nullable
4039  {
4040  DBUG_ASSERT(idx != table_share->primary_key); // PK can't be nullable
4041  DBUG_ASSERT(*(key+offset)==0); // Null values not allowed in key
4042  // Value is imm. after NULL indicator
4043  paramValues[map[i]]= NdbQueryParamValue(key+offset+1,shrinkVarChar);
4044  }
4045  else // Non-nullable column
4046  {
4047  paramValues[map[i]]= NdbQueryParamValue(key+offset,shrinkVarChar);
4048  }
4049  offset+= key_part->store_length;
4050  }
4051 
4052  const int ret= create_pushed_join(paramValues, key_def->user_defined_key_parts);
4053  DBUG_RETURN(ret);
4054 }
4055 
4056 #endif
4057 
4059 static uint
4060 count_key_columns(const KEY *key_info, const key_range *key)
4061 {
4062  KEY_PART_INFO *first_key_part= key_info->key_part;
4063  KEY_PART_INFO *key_part_end= first_key_part + key_info->user_defined_key_parts;
4064  KEY_PART_INFO *key_part;
4065  uint length= 0;
4066  for(key_part= first_key_part; key_part < key_part_end; key_part++)
4067  {
4068  if (length >= key->length)
4069  break;
4070  length+= key_part->store_length;
4071  }
4072  return key_part - first_key_part;
4073 }
4074 
4075 /* Helper method to compute NDB index bounds. Note: does not set range_no. */
4076 /* Stats queries may differ so add "from" 0:normal 1:RIR 2:RPK. */
4077 void
4078 compute_index_bounds(NdbIndexScanOperation::IndexBound & bound,
4079  const KEY *key_info,
4080  const key_range *start_key, const key_range *end_key,
4081  int from)
4082 {
4083  DBUG_ENTER("ha_ndbcluster::compute_index_bounds");
4084  DBUG_PRINT("info", ("from: %d", from));
4085 
4086 #ifndef DBUG_OFF
4087  DBUG_PRINT("info", ("key parts: %u length: %u",
4088  key_info->user_defined_key_parts, key_info->key_length));
4089  {
4090  for (uint j= 0; j <= 1; j++)
4091  {
4092  const key_range* kr= (j == 0 ? start_key : end_key);
4093  if (kr)
4094  {
4095  DBUG_PRINT("info", ("key range %u: length: %u map: %lx flag: %d",
4096  j, kr->length, kr->keypart_map, kr->flag));
4097  DBUG_DUMP("key", kr->key, kr->length);
4098  }
4099  else
4100  {
4101  DBUG_PRINT("info", ("key range %u: none", j));
4102  }
4103  }
4104  }
4105 #endif
4106 
4107  if (start_key)
4108  {
4109  bound.low_key= (const char*)start_key->key;
4110  bound.low_key_count= count_key_columns(key_info, start_key);
4111  bound.low_inclusive=
4112  start_key->flag != HA_READ_AFTER_KEY &&
4113  start_key->flag != HA_READ_BEFORE_KEY;
4114  }
4115  else
4116  {
4117  bound.low_key= NULL;
4118  bound.low_key_count= 0;
4119  }
4120 
4121  /* RIR query for x >= 1 inexplicably passes HA_READ_KEY_EXACT. */
4122  if (start_key &&
4123  (start_key->flag == HA_READ_KEY_EXACT ||
4124  start_key->flag == HA_READ_PREFIX_LAST) &&
4125  from != 1)
4126  {
4127  bound.high_key= bound.low_key;
4128  bound.high_key_count= bound.low_key_count;
4129  bound.high_inclusive= TRUE;
4130  }
4131  else if (end_key)
4132  {
4133  bound.high_key= (const char*)end_key->key;
4134  bound.high_key_count= count_key_columns(key_info, end_key);
4135  /*
4136  For some reason, 'where b >= 1 and b <= 3' uses HA_READ_AFTER_KEY for
4137  the end_key.
4138  So HA_READ_AFTER_KEY in end_key sets high_inclusive, even though in
4139  start_key it does not set low_inclusive.
4140  */
4141  bound.high_inclusive= end_key->flag != HA_READ_BEFORE_KEY;
4142  if (end_key->flag == HA_READ_KEY_EXACT ||
4143  end_key->flag == HA_READ_PREFIX_LAST)
4144  {
4145  bound.low_key= bound.high_key;
4146  bound.low_key_count= bound.high_key_count;
4147  bound.low_inclusive= TRUE;
4148  }
4149  }
4150  else
4151  {
4152  bound.high_key= NULL;
4153  bound.high_key_count= 0;
4154  }
4155  DBUG_PRINT("info", ("start_flag=%d end_flag=%d"
4156  " lo_keys=%d lo_incl=%d hi_keys=%d hi_incl=%d",
4157  start_key?start_key->flag:0, end_key?end_key->flag:0,
4158  bound.low_key_count,
4159  bound.low_key_count?bound.low_inclusive:0,
4160  bound.high_key_count,
4161  bound.high_key_count?bound.high_inclusive:0));
4162  DBUG_VOID_RETURN;
4163 }
4164 
4169 int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
4170  const key_range *end_key,
4171  bool sorted, bool descending,
4172  uchar* buf, part_id_range *part_spec)
4173 {
4174  NdbTransaction *trans;
4176  int error;
4177 
4178  DBUG_ENTER("ha_ndbcluster::ordered_index_scan");
4179  DBUG_PRINT("enter", ("index: %u, sorted: %d, descending: %d read_set=0x%x",
4180  active_index, sorted, descending, table->read_set->bitmap[0]));
4181  DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname));
4182 
4183  // Check that sorted seems to be initialised
4184  DBUG_ASSERT(sorted == 0 || sorted == 1);
4185 
4186  if (unlikely(!(trans= get_transaction(error))))
4187  {
4188  DBUG_RETURN(error);
4189  }
4190 
4191  if ((error= close_scan()))
4192  DBUG_RETURN(error);
4193 
4194  const NdbOperation::LockMode lm = get_ndb_lock_mode(m_lock.type);
4195 
4196  const NdbRecord *key_rec= m_index[active_index].ndb_record_key;
4197  const NdbRecord *row_rec= m_ndb_record;
4198 
4200  NdbIndexScanOperation::IndexBound *pbound = NULL;
4201  if (start_key != NULL || end_key != NULL)
4202  {
4203  /*
4204  Compute bounds info, reversing range boundaries
4205  if descending
4206  */
4207  compute_index_bounds(bound,
4208  table->key_info + active_index,
4209  (descending?
4210  end_key : start_key),
4211  (descending?
4212  start_key : end_key),
4213  0);
4214  bound.range_no = 0;
4215  pbound = &bound;
4216  }
4217 
4218 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
4219  if (check_if_pushable(NdbQueryOperationDef::OrderedIndexScan, active_index,
4220  sorted))
4221  {
4222  const int error= create_pushed_join();
4223  if (unlikely(error))
4224  DBUG_RETURN(error);
4225 
4226  NdbQuery* const query= m_active_query;
4227  if (sorted && query->getQueryOperation((uint)PUSHED_ROOT)
4228  ->setOrdering(descending ? NdbQueryOptions::ScanOrdering_descending
4229  : NdbQueryOptions::ScanOrdering_ascending))
4230  {
4231  ERR_RETURN(query->getNdbError());
4232  }
4233 
4234  if (pbound && query->setBound(key_rec, pbound)!=0)
4235  ERR_RETURN(query->getNdbError());
4236 
4237  m_thd_ndb->m_scan_count++;
4238 
4239  bool prunable = false;
4240  if (unlikely(query->isPrunable(prunable) != 0))
4241  ERR_RETURN(query->getNdbError());
4242  if (prunable)
4243  m_thd_ndb->m_pruned_scan_count++;
4244 
4245  DBUG_ASSERT(!uses_blob_value(table->read_set)); // Can't have BLOB in pushed joins (yet)
4246  }
4247  else
4248 #endif
4249  {
4250  if (m_pushed_join_operation == PUSHED_ROOT)
4251  {
4252  m_thd_ndb->m_pushed_queries_dropped++;
4253  }
4254 
4256  options.optionsPresent=NdbScanOperation::ScanOptions::SO_SCANFLAGS;
4257  options.scan_flags=0;
4258 
4260  if (table_share->primary_key == MAX_KEY)
4261  get_hidden_fields_scan(&options, gets);
4262 
4263  if (lm == NdbOperation::LM_Read)
4264  options.scan_flags|= NdbScanOperation::SF_KeyInfo;
4265  if (sorted)
4266  options.scan_flags|= NdbScanOperation::SF_OrderByFull;
4267  if (descending)
4268  options.scan_flags|= NdbScanOperation::SF_Descending;
4269 
4270  /* Partition pruning */
4271  if (m_use_partition_pruning &&
4272  m_user_defined_partitioning && part_spec != NULL &&
4273  part_spec->start_part == part_spec->end_part)
4274  {
4275  /* Explicitly set partition id when pruning User-defined partitioned scan */
4276  options.partitionId = part_spec->start_part;
4277  options.optionsPresent |= NdbScanOperation::ScanOptions::SO_PARTITION_ID;
4278  }
4279 
4280  NdbInterpretedCode code(m_table);
4281  if (m_cond && m_cond->generate_scan_filter(&code, &options))
4282  ERR_RETURN(code.getNdbError());
4283 
4284  if (!(op= trans->scanIndex(key_rec, row_rec, lm,
4285  (uchar *)(table->read_set->bitmap),
4286  pbound,
4287  &options,
4289  ERR_RETURN(trans->getNdbError());
4290 
4291  DBUG_PRINT("info", ("Is scan pruned to 1 partition? : %u", op->getPruned()));
4292  m_thd_ndb->m_scan_count++;
4293  m_thd_ndb->m_pruned_scan_count += (op->getPruned()? 1 : 0);
4294 
4295  if (uses_blob_value(table->read_set) &&
4296  get_blob_values(op, NULL, table->read_set) != 0)
4297  ERR_RETURN(op->getNdbError());
4298 
4299  m_active_cursor= op;
4300  }
4301 
4302  if (sorted)
4303  {
4304  m_thd_ndb->m_sorted_scan_count++;
4305  }
4306 
4307  if (execute_no_commit(m_thd_ndb, trans, m_ignore_no_key) != 0)
4308  DBUG_RETURN(ndb_err(trans));
4309 
4310  DBUG_RETURN(next_result(buf));
4311 }
4312 
4313 static
4314 int
4315 guess_scan_flags(NdbOperation::LockMode lm,
4316  const NDBTAB* tab, const MY_BITMAP* readset)
4317 {
4318  int flags= 0;
4319  flags|= (lm == NdbOperation::LM_Read) ? NdbScanOperation::SF_KeyInfo : 0;
4320  if (tab->checkColumns(0, 0) & 2)
4321  {
4322  int ret = tab->checkColumns(readset->bitmap, no_bytes_in_map(readset));
4323 
4324  if (ret & 2)
4325  { // If disk columns...use disk scan
4326  flags |= NdbScanOperation::SF_DiskScan;
4327  }
4328  else if ((ret & 4) == 0 && (lm == NdbOperation::LM_Exclusive))
4329  {
4330  // If no mem column is set and exclusive...guess disk scan
4331  flags |= NdbScanOperation::SF_DiskScan;
4332  }
4333  }
4334  return flags;
4335 }
4336 
4337 /*
4338  Start full table scan in NDB or unique index scan
4339  */
4340 
4341 int ha_ndbcluster::full_table_scan(const KEY* key_info,
4342  const key_range *start_key,
4343  const key_range *end_key,
4344  uchar *buf)
4345 {
4346  int error;
4347  NdbTransaction *trans= m_thd_ndb->trans;
4348  part_id_range part_spec;
4349  bool use_set_part_id= FALSE;
4351 
4352  DBUG_ENTER("full_table_scan");
4353  DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
4354 
4355  if (m_use_partition_pruning && m_user_defined_partitioning)
4356  {
4357  DBUG_ASSERT(m_pushed_join_operation != PUSHED_ROOT);
4358  part_spec.start_part= 0;
4359  part_spec.end_part= m_part_info->get_tot_partitions() - 1;
4360  prune_partition_set(table, &part_spec);
4361  DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
4362  part_spec.start_part, part_spec.end_part));
4363  /*
4364  If partition pruning has found no partition in set
4365  we can return HA_ERR_END_OF_FILE
4366  */
4367  if (part_spec.start_part > part_spec.end_part)
4368  {
4369  DBUG_RETURN(HA_ERR_END_OF_FILE);
4370  }
4371 
4372  if (part_spec.start_part == part_spec.end_part)
4373  {
4374  /*
4375  * Only one partition is required to scan, if sorted is required
4376  * don't need it anymore since output from one ordered partitioned
4377  * index is always sorted.
4378  *
4379  * Note : This table scan pruning currently only occurs for
4380  * UserDefined partitioned tables.
4381  * It could be extended to occur for natively partitioned tables if
4382  * the Partitioning layer can make a key (e.g. start or end key)
4383  * available so that we can determine the correct pruning in the
4384  * NDBAPI layer.
4385  */
4386  use_set_part_id= TRUE;
4387  if (!trans)
4388  if (unlikely(!(trans= get_transaction_part_id(part_spec.start_part,
4389  error))))
4390  DBUG_RETURN(error);
4391  }
4392  }
4393  if (!trans)
4394  if (unlikely(!(trans= start_transaction(error))))
4395  DBUG_RETURN(error);
4396 
4397  const NdbOperation::LockMode lm = get_ndb_lock_mode(m_lock.type);
4399  options.optionsPresent = (NdbScanOperation::ScanOptions::SO_SCANFLAGS |
4400  NdbScanOperation::ScanOptions::SO_PARALLEL);
4401  options.scan_flags = guess_scan_flags(lm, m_table, table->read_set);
4402  options.parallel= DEFAULT_PARALLELISM;
4403 
4404  if (use_set_part_id) {
4405  assert(m_user_defined_partitioning);
4406  options.optionsPresent|= NdbScanOperation::ScanOptions::SO_PARTITION_ID;
4407  options.partitionId = part_spec.start_part;
4408  };
4409 
4410  if (table_share->primary_key == MAX_KEY)
4411  get_hidden_fields_scan(&options, gets);
4412 
4413 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
4414  if (check_if_pushable(NdbQueryOperationDef::TableScan))
4415  {
4416  const int error= create_pushed_join();
4417  if (unlikely(error))
4418  DBUG_RETURN(error);
4419 
4420  m_thd_ndb->m_scan_count++;
4421  DBUG_ASSERT(!uses_blob_value(table->read_set)); // Can't have BLOB in pushed joins (yet)
4422  }
4423  else
4424 #endif
4425  {
4426  if (m_pushed_join_operation == PUSHED_ROOT)
4427  {
4428  m_thd_ndb->m_pushed_queries_dropped++;
4429  }
4430 
4431  NdbScanOperation *op;
4432  NdbInterpretedCode code(m_table);
4433 
4434  if (!key_info)
4435  {
4436  if (m_cond && m_cond->generate_scan_filter(&code, &options))
4437  ERR_RETURN(code.getNdbError());
4438  }
4439  else
4440  {
4441  /* Unique index scan in NDB (full table scan with scan filter) */
4442  DBUG_PRINT("info", ("Starting unique index scan"));
4443  if (!m_cond)
4444  m_cond= new ha_ndbcluster_cond;
4445 
4446  if (!m_cond)
4447  {
4448  my_errno= HA_ERR_OUT_OF_MEM;
4449  DBUG_RETURN(my_errno);
4450  }
4451  if (m_cond->generate_scan_filter_from_key(&code, &options, key_info, start_key, end_key, buf))
4452  ERR_RETURN(code.getNdbError());
4453  }
4454 
4455  if (!(op= trans->scanTable(m_ndb_record, lm,
4456  (uchar *)(table->read_set->bitmap),
4457  &options, sizeof(NdbScanOperation::ScanOptions))))
4458  ERR_RETURN(trans->getNdbError());
4459 
4460  m_thd_ndb->m_scan_count++;
4461  m_thd_ndb->m_pruned_scan_count += (op->getPruned()? 1 : 0);
4462 
4463  DBUG_ASSERT(m_active_cursor==NULL);
4464  m_active_cursor= op;
4465 
4466  if (uses_blob_value(table->read_set) &&
4467  get_blob_values(op, NULL, table->read_set) != 0)
4468  ERR_RETURN(op->getNdbError());
4469  } // if (check_if_pushable(NdbQueryOperationDef::TableScan))
4470 
4471  if (execute_no_commit(m_thd_ndb, trans, m_ignore_no_key) != 0)
4472  DBUG_RETURN(ndb_err(trans));
4473  DBUG_PRINT("exit", ("Scan started successfully"));
4474  DBUG_RETURN(next_result(buf));
4475 } // ha_ndbcluster::full_table_scan()
4476 
4477 int
4478 ha_ndbcluster::set_auto_inc(THD *thd, Field *field)
4479 {
4480  DBUG_ENTER("ha_ndbcluster::set_auto_inc");
4481  bool read_bit= bitmap_is_set(table->read_set, field->field_index);
4482  bitmap_set_bit(table->read_set, field->field_index);
4483  Uint64 next_val= (Uint64) field->val_int() + 1;
4484  if (!read_bit)
4485  bitmap_clear_bit(table->read_set, field->field_index);
4486  DBUG_RETURN(set_auto_inc_val(thd, next_val));
4487 }
4488 
4489 inline
4490 int
4491 ha_ndbcluster::set_auto_inc_val(THD *thd, Uint64 value)
4492 {
4493  Ndb *ndb= get_ndb(thd);
4494  DBUG_ENTER("ha_ndbcluster::set_auto_inc_val");
4495 #ifndef DBUG_OFF
4496  char buff[22];
4497  DBUG_PRINT("info",
4498  ("Trying to set next auto increment value to %s",
4499  llstr(value, buff)));
4500 #endif
4501  if (ndb->checkUpdateAutoIncrementValue(m_share->tuple_id_range, value))
4502  {
4503  Ndb_tuple_id_range_guard g(m_share);
4504  if (ndb->setAutoIncrementValue(m_table, g.range, value, TRUE)
4505  == -1)
4506  ERR_RETURN(ndb->getNdbError());
4507  }
4508  DBUG_RETURN(0);
4509 }
4510 
4511 Uint32
4512 ha_ndbcluster::setup_get_hidden_fields(NdbOperation::GetValueSpec gets[2])
4513 {
4514  Uint32 num_gets= 0;
4515  /*
4516  We need to read the hidden primary key, and possibly the FRAGMENT
4517  pseudo-column.
4518  */
4519  gets[num_gets].column= get_hidden_key_column();
4520  gets[num_gets].appStorage= &m_ref;
4521  num_gets++;
4522  if (m_user_defined_partitioning)
4523  {
4524  /* Need to read partition id to support ORDER BY columns. */
4525  gets[num_gets].column= NdbDictionary::Column::FRAGMENT;
4526  gets[num_gets].appStorage= &m_part_id;
4527  num_gets++;
4528  }
4529  return num_gets;
4530 }
4531 
4532 void
4533 ha_ndbcluster::get_hidden_fields_keyop(NdbOperation::OperationOptions *options,
4535 {
4536  Uint32 num_gets= setup_get_hidden_fields(gets);
4537  options->optionsPresent|= NdbOperation::OperationOptions::OO_GETVALUE;
4538  options->extraGetValues= gets;
4539  options->numExtraGetValues= num_gets;
4540 }
4541 
4542 void
4543 ha_ndbcluster::get_hidden_fields_scan(NdbScanOperation::ScanOptions *options,
4545 {
4546  Uint32 num_gets= setup_get_hidden_fields(gets);
4547  options->optionsPresent|= NdbScanOperation::ScanOptions::SO_GETVALUE;
4548  options->extraGetValues= gets;
4549  options->numExtraGetValues= num_gets;
4550 }
4551 
4552 inline void
4553 ha_ndbcluster::eventSetAnyValue(THD *thd,
4554  NdbOperation::OperationOptions *options) const
4555 {
4556  options->anyValue= 0;
4557  if (unlikely(m_slow_path))
4558  {
4559  /*
4560  Ignore TNTO_NO_LOGGING for slave thd. It is used to indicate
4561  log-slave-updates option. This is instead handled in the
4562  injector thread, by looking explicitly at the
4563  opt_log_slave_updates flag.
4564  */
4565  Thd_ndb *thd_ndb= get_thd_ndb(thd);
4566  if (thd->slave_thread)
4567  {
4568  /*
4569  Slave-thread, we are applying a replicated event.
4570  We set the server_id to the value received from the log which
4571  may be a composite of server_id and other data according
4572  to the server_id_bits option.
4573  In future it may be useful to support *not* mapping composite
4574  AnyValues to/from Binlogged server-ids
4575  */
4576  options->optionsPresent |= NdbOperation::OperationOptions::OO_ANYVALUE;
4577  options->anyValue = thd_unmasked_server_id(thd);
4578  }
4579  else if (thd_ndb->trans_options & TNTO_NO_LOGGING)
4580  {
4581  options->optionsPresent |= NdbOperation::OperationOptions::OO_ANYVALUE;
4582  ndbcluster_anyvalue_set_nologging(options->anyValue);
4583  }
4584  }
4585 #ifndef DBUG_OFF
4586  /*
4587  MySQLD will set the user-portion of AnyValue (if any) to all 1s
4588  This tests code filtering ServerIds on the value of server-id-bits.
4589  */
4590  const char* p = getenv("NDB_TEST_ANYVALUE_USERDATA");
4591  if (p != 0 && *p != 0 && *p != '0' && *p != 'n' && *p != 'N')
4592  {
4593  options->optionsPresent |= NdbOperation::OperationOptions::OO_ANYVALUE;
4594  dbug_ndbcluster_anyvalue_set_userbits(options->anyValue);
4595  }
4596 #endif
4597 }
4598 
4599 #ifdef HAVE_NDB_BINLOG
4600 
4610 int
4611 ha_ndbcluster::prepare_conflict_detection(enum_conflicting_op_type op_type,
4612  const NdbRecord* key_rec,
4613  const uchar* old_data,
4614  const uchar* new_data,
4617 {
4618  DBUG_ENTER("prepare_conflict_detection");
4619 
4620  int res = 0;
4621  const st_conflict_fn_def* conflict_fn = m_share->m_cfn_share->m_conflict_fn;
4622  assert( conflict_fn != NULL );
4623 
4624 
4625  /*
4626  Prepare interpreted code for operation (update + delete only) according
4627  to algorithm used
4628  */
4629  if (op_type != WRITE_ROW)
4630  {
4631  res = conflict_fn->prep_func(m_share->m_cfn_share,
4632  op_type,
4633  old_data,
4634  new_data,
4635  table->write_set,
4636  code);
4637 
4638  if (!res)
4639  {
4640  /* Attach conflict detecting filter program to operation */
4641  options->optionsPresent|=NdbOperation::OperationOptions::OO_INTERPRETED;
4642  options->interpretedCode= code;
4643  }
4644  } // if (op_type != WRITE_ROW)
4645 
4646  g_ndb_slave_state.current_conflict_defined_op_count++;
4647 
4648  /* Now save data for potential insert to exceptions table... */
4649  const uchar* row_to_save = (op_type == DELETE_ROW)? old_data : new_data;
4650  Ndb_exceptions_data ex_data;
4651  ex_data.share= m_share;
4652  ex_data.key_rec= key_rec;
4653  ex_data.op_type= op_type;
4654  /*
4655  We need to save the row data for possible conflict resolution after
4656  execute().
4657  */
4658  ex_data.row= copy_row_to_buffer(m_thd_ndb, row_to_save);
4659  uchar* ex_data_buffer= get_buffer(m_thd_ndb, sizeof(ex_data));
4660  if (ex_data.row == NULL || ex_data_buffer == NULL)
4661  {
4662  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
4663  }
4664  memcpy(ex_data_buffer, &ex_data, sizeof(ex_data));
4665 
4666  /* Store ptr to exceptions data in operation 'customdata' ptr */
4667  options->optionsPresent|= NdbOperation::OperationOptions::OO_CUSTOMDATA;
4668  options->customData= (void*)ex_data_buffer;
4669 
4670  DBUG_RETURN(0);
4671 }
4672 
4686 int
4687 handle_conflict_op_error(Thd_ndb* thd_ndb,
4688  NdbTransaction* trans,
4689  const NdbError& err,
4690  const NdbOperation* op)
4691 {
4692  DBUG_ENTER("handle_conflict_op_error");
4693  DBUG_PRINT("info", ("ndb error: %d", err.code));
4694 
4695  if ((err.code == (int) error_conflict_fn_violation) ||
4696  (err.code == (int) error_op_after_refresh_op) ||
4699  {
4700  DBUG_PRINT("info",
4701  ("err.code %s (int) error_conflict_fn_violation, "
4702  "err.classification %s",
4703  err.code == (int) error_conflict_fn_violation ? "==" : "!=",
4704  err.classification
4706  ? "== NdbError::ConstraintViolation"
4708  ? "== NdbError::NoDataFound" : "!=")));
4709 
4710  enum_conflict_cause conflict_cause;
4711 
4712  if ((err.code == (int) error_conflict_fn_violation) ||
4713  (err.code == (int) error_op_after_refresh_op))
4714  {
4715  conflict_cause= ROW_IN_CONFLICT;
4716  }
4718  {
4719  conflict_cause= ROW_ALREADY_EXISTS;
4720  }
4721  else
4722  {
4723  assert(err.classification == NdbError::NoDataFound);
4724  conflict_cause= ROW_DOES_NOT_EXIST;
4725  }
4726 
4727  const void* buffer=op->getCustomData();
4728  assert(buffer);
4729  Ndb_exceptions_data ex_data;
4730  memcpy(&ex_data, buffer, sizeof(ex_data));
4731  NDB_SHARE *share= ex_data.share;
4732  const NdbRecord* key_rec= ex_data.key_rec;
4733  const uchar* row= ex_data.row;
4734  enum_conflicting_op_type op_type = ex_data.op_type;
4735  DBUG_ASSERT(share != NULL && row != NULL);
4736 
4737  NDB_CONFLICT_FN_SHARE* cfn_share= share->m_cfn_share;
4738  if (cfn_share)
4739  {
4740  enum_conflict_fn_type cft = cfn_share->m_conflict_fn->type;
4741  bool haveExTable = cfn_share->m_ex_tab != NULL;
4742 
4743  g_ndb_slave_state.current_violation_count[cft]++;
4744 
4745  {
4746  NdbError handle_error;
4747  if (handle_row_conflict(cfn_share,
4748  share->table_name,
4749  key_rec,
4750  row,
4751  op_type,
4752  conflict_cause,
4753  err,
4754  trans,
4755  handle_error))
4756  {
4757  /* Error with handling of row conflict */
4758  char msg[FN_REFLEN];
4759  my_snprintf(msg, sizeof(msg), "Row conflict handling "
4760  "on table %s hit Ndb error %d '%s'",
4761  share->table_name,
4762  handle_error.code,
4763  handle_error.message);
4764 
4765  if (handle_error.status == NdbError::TemporaryError)
4766  {
4767  /* Slave will roll back and retry entire transaction. */
4768  ERR_RETURN(handle_error);
4769  }
4770  else
4771  {
4772  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
4773  ER_EXCEPTIONS_WRITE_ERROR,
4774  ER(ER_EXCEPTIONS_WRITE_ERROR), msg);
4775  /* Slave will stop replication. */
4776  DBUG_RETURN(ER_EXCEPTIONS_WRITE_ERROR);
4777  }
4778  }
4779  }
4780 
4781 
4782  if (haveExTable)
4783  {
4784  NdbError ex_err;
4785  if (write_conflict_row(share, trans, row, ex_err))
4786  {
4787  char msg[FN_REFLEN];
4788  my_snprintf(msg, sizeof(msg), "table %s NDB error %d '%s'",
4789  cfn_share->m_ex_tab->getName(),
4790  ex_err.code, ex_err.message);
4791 
4792  NdbDictionary::Dictionary* dict= thd_ndb->ndb->getDictionary();
4793 
4794  if (ex_err.classification == NdbError::SchemaError)
4795  {
4796  dict->removeTableGlobal(*(cfn_share->m_ex_tab), false);
4797  cfn_share->m_ex_tab= NULL;
4798  }
4799  else if (ex_err.status == NdbError::TemporaryError)
4800  {
4801  /* Slave will roll back and retry entire transaction. */
4802  ERR_RETURN(ex_err);
4803  }
4804  else
4805  {
4806  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
4807  ER_EXCEPTIONS_WRITE_ERROR,
4808  ER(ER_EXCEPTIONS_WRITE_ERROR), msg);
4809  /* Slave will stop replication. */
4810  DBUG_RETURN(ER_EXCEPTIONS_WRITE_ERROR);
4811  }
4812  }
4813  } // if (haveExTable)
4814 
4815  DBUG_RETURN(0);
4816  }
4817  else
4818  {
4819  DBUG_PRINT("info", ("missing cfn_share"));
4820  DBUG_RETURN(0); // TODO : Correct?
4821  }
4822  }
4823  else
4824  {
4825  /* Non conflict related error */
4826  DBUG_PRINT("info", ("err.code == %u", err.code));
4827  DBUG_RETURN(err.code);
4828  }
4829 
4830  DBUG_RETURN(0); // Reachable?
4831 }
4832 #endif /* HAVE_NDB_BINLOG */
4833 
4834 
4835 #ifdef HAVE_NDB_BINLOG
4836 /*
4837  is_serverid_local
4838 */
4839 static bool is_serverid_local(Uint32 serverid)
4840 {
4841  /*
4842  If it's not our serverid, check the
4843  IGNORE_SERVER_IDS setting to check if
4844  it's local.
4845  */
4846  return ((serverid == ::server_id) ||
4847  ndb_mi_get_ignore_server_id(serverid));
4848 }
4849 #endif
4850 
4851 int ha_ndbcluster::write_row(uchar *record)
4852 {
4853  DBUG_ENTER("ha_ndbcluster::write_row");
4854 #ifdef HAVE_NDB_BINLOG
4855  if (m_share == ndb_apply_status_share && table->in_use->slave_thread)
4856  {
4857  uint32 row_server_id, master_server_id= ndb_mi_get_master_server_id();
4858  uint64 row_epoch;
4859  memcpy(&row_server_id, table->field[0]->ptr + (record - table->record[0]),
4860  sizeof(row_server_id));
4861  memcpy(&row_epoch, table->field[1]->ptr + (record - table->record[0]),
4862  sizeof(row_epoch));
4863  g_ndb_slave_state.atApplyStatusWrite(master_server_id,
4864  row_server_id,
4865  row_epoch,
4866  is_serverid_local(row_server_id));
4867  }
4868 #endif /* HAVE_NDB_BINLOG */
4869  DBUG_RETURN(ndb_write_row(record, FALSE, FALSE));
4870 }
4871 
4875 int ha_ndbcluster::ndb_write_row(uchar *record,
4876  bool primary_key_update,
4877  bool batched_update)
4878 {
4879  bool has_auto_increment;
4880  const NdbOperation *op;
4881  THD *thd= table->in_use;
4882  Thd_ndb *thd_ndb= m_thd_ndb;
4883  NdbTransaction *trans;
4884  uint32 part_id;
4885  int error;
4887  Uint32 num_sets= 0;
4888  DBUG_ENTER("ha_ndbcluster::ndb_write_row");
4889 
4890  error = check_slave_state(thd);
4891  if (unlikely(error))
4892  DBUG_RETURN(error);
4893 
4894  has_auto_increment= (table->next_number_field && record == table->record[0]);
4895 
4896  if (has_auto_increment && table_share->primary_key != MAX_KEY)
4897  {
4898  /*
4899  * Increase any auto_incremented primary key
4900  */
4901  m_skip_auto_increment= FALSE;
4902  if ((error= update_auto_increment()))
4903  DBUG_RETURN(error);
4904  m_skip_auto_increment= (insert_id_for_cur_row == 0);
4905  }
4906 
4907  /*
4908  * If IGNORE the ignore constraint violations on primary and unique keys
4909  */
4910  if (!m_use_write && m_ignore_dup_key)
4911  {
4912  /*
4913  compare if expression with that in start_bulk_insert()
4914  start_bulk_insert will set parameters to ensure that each
4915  write_row is committed individually
4916  */
4917  int peek_res= peek_indexed_rows(record, NDB_INSERT);
4918 
4919  if (!peek_res)
4920  {
4921  DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
4922  }
4923  if (peek_res != HA_ERR_KEY_NOT_FOUND)
4924  DBUG_RETURN(peek_res);
4925  }
4926 
4927  bool uses_blobs= uses_blob_value(table->write_set);
4928 
4929  Uint64 auto_value;
4930  const NdbRecord *key_rec;
4931  const uchar *key_row;
4932  if (table_share->primary_key == MAX_KEY)
4933  {
4934  /* Table has hidden primary key. */
4935  Ndb *ndb= get_ndb(thd);
4936  uint retries= NDB_AUTO_INCREMENT_RETRIES;
4937  int retry_sleep= 30; /* 30 milliseconds, transaction */
4938  for (;;)
4939  {
4940  Ndb_tuple_id_range_guard g(m_share);
4941  if (ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1000) == -1)
4942  {
4943  if (--retries && !thd->killed &&
4945  {
4946  do_retry_sleep(retry_sleep);
4947  continue;
4948  }
4949  ERR_RETURN(ndb->getNdbError());
4950  }
4951  break;
4952  }
4953  sets[num_sets].column= get_hidden_key_column();
4954  sets[num_sets].value= &auto_value;
4955  num_sets++;
4956  key_rec= m_ndb_hidden_key_record;
4957  key_row= (const uchar *)&auto_value;
4958  }
4959  else
4960  {
4961  key_rec= m_index[table_share->primary_key].ndb_unique_record_row;
4962  key_row= record;
4963  }
4964 
4965  trans= thd_ndb->trans;
4966  if (m_user_defined_partitioning)
4967  {
4968  DBUG_ASSERT(m_use_partition_pruning);
4969  longlong func_value= 0;
4970  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
4971  error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
4972  dbug_tmp_restore_column_map(table->read_set, old_map);
4973  if (unlikely(error))
4974  {
4975  m_part_info->err_value= func_value;
4976  DBUG_RETURN(error);
4977  }
4978  {
4979  /*
4980  We need to set the value of the partition function value in
4981  NDB since the NDB kernel doesn't have easy access to the function
4982  to calculate the value.
4983  */
4984  if (func_value >= INT_MAX32)
4985  func_value= INT_MAX32;
4986  sets[num_sets].column= get_partition_id_column();
4987  sets[num_sets].value= &func_value;
4988  num_sets++;
4989  }
4990  if (!trans)
4991  if (unlikely(!(trans= start_transaction_part_id(part_id, error))))
4992  DBUG_RETURN(error);
4993  }
4994  else if (!trans)
4995  {
4996  if (unlikely(!(trans= start_transaction_row(key_rec, key_row, error))))
4997  DBUG_RETURN(error);
4998  }
4999  DBUG_ASSERT(trans);
5000 
5001  ha_statistic_increment(&SSV::ha_write_count);
5002 
5003  /*
5004  Setup OperationOptions
5005  */
5007  NdbOperation::OperationOptions *poptions = NULL;
5008  options.optionsPresent=0;
5009 
5010  eventSetAnyValue(thd, &options);
5011  bool need_flush= add_row_check_if_batch_full(thd_ndb);
5012 
5013  const Uint32 authorValue = 1;
5014  if ((thd->slave_thread) &&
5015  (m_table->getExtraRowAuthorBits()))
5016  {
5017  /* Set author to indicate slave updated last */
5018  sets[num_sets].column= NdbDictionary::Column::ROW_AUTHOR;
5019  sets[num_sets].value= &authorValue;
5020  num_sets++;
5021  }
5022 
5023  if (m_user_defined_partitioning)
5024  {
5025  options.optionsPresent |= NdbOperation::OperationOptions::OO_PARTITION_ID;
5026  options.partitionId= part_id;
5027  }
5028  if (num_sets)
5029  {
5030  options.optionsPresent |= NdbOperation::OperationOptions::OO_SETVALUE;
5031  options.extraSetValues= sets;
5032  options.numExtraSetValues= num_sets;
5033  }
5034  if (thd->slave_thread || THDVAR(thd, deferred_constraints))
5035  {
5036  options.optionsPresent |=
5037  NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
5038  }
5039 
5040  if (options.optionsPresent != 0)
5041  poptions=&options;
5042 
5043  const Uint32 bitmapSz= (NDB_MAX_ATTRIBUTES_IN_TABLE + 31)/32;
5044  uint32 tmpBitmapSpace[bitmapSz];
5045  MY_BITMAP tmpBitmap;
5046  MY_BITMAP *user_cols_written_bitmap;
5047 #ifdef HAVE_NDB_BINLOG
5048  bool haveConflictFunction =
5049  (thd->slave_thread &&
5050  m_share->m_cfn_share &&
5051  m_share->m_cfn_share->m_conflict_fn);
5052 #endif
5053 
5054  if (m_use_write
5055 #ifdef HAVE_NDB_BINLOG
5056  /* Conflict detection must use normal Insert */
5057  && !haveConflictFunction
5058 #endif
5059  )
5060  {
5061  /* Should we use the supplied table writeset or not?
5062  * For a REPLACE command, we should ignore it, and write
5063  * all columns to get correct REPLACE behaviour.
5064  * For applying Binlog events, we need to use the writeset
5065  * to avoid trampling unchanged columns when an update is
5066  * logged as a WRITE
5067  */
5068  bool useWriteSet= isManualBinlogExec(thd);
5069 
5070 #ifdef HAVE_NDB_BINLOG
5071  /* Slave always uses writeset
5072  * TODO : What about SBR replicating a
5073  * REPLACE command?
5074  */
5075  useWriteSet |= thd->slave_thread;
5076 #endif
5077  uchar* mask;
5078 
5079  if (useWriteSet)
5080  {
5081  user_cols_written_bitmap= table->write_set;
5082  mask= (uchar *)(user_cols_written_bitmap->bitmap);
5083  }
5084  else
5085  {
5086  user_cols_written_bitmap= NULL;
5087  mask= NULL;
5088  }
5089  /* TODO : Add conflict detection etc when interpreted write supported */
5090  op= trans->writeTuple(key_rec, (const char *)key_row, m_ndb_record,
5091  (char *)record, mask,
5092  poptions, sizeof(NdbOperation::OperationOptions));
5093  }
5094  else
5095  {
5096 #ifdef HAVE_NDB_BINLOG
5097  if (haveConflictFunction)
5098  {
5099  /* Conflict detection in slave thread */
5100  if (unlikely((error = prepare_conflict_detection(WRITE_ROW,
5101  key_rec,
5102  NULL, /* old_data */
5103  record, /* new_data */
5104  NULL, /* code */
5105  &options))))
5106  DBUG_RETURN(error);
5107  }
5108 #endif
5109  uchar *mask;
5110 
5111  /* Check whether Ndb table definition includes any default values. */
5112  if (m_table->hasDefaultValues())
5113  {
5114  DBUG_PRINT("info", ("Not sending values for native defaulted columns"));
5115 
5116  /*
5117  If Ndb is unaware of the table's defaults, we must provide all column values to the insert.
5118  This is done using a NULL column mask.
5119  If Ndb is aware of the table's defaults, we only need to provide
5120  the columns explicitly mentioned in the write set,
5121  plus any extra columns required due to bug#41616.
5122  plus the primary key columns required due to bug#42238.
5123  */
5124  /*
5125  The following code for setting user_cols_written_bitmap
5126  should be removed after BUG#41616 and Bug#42238 are fixed
5127  */
5128  /* Copy table write set so that we can add to it */
5129  user_cols_written_bitmap= &tmpBitmap;
5130  bitmap_init(user_cols_written_bitmap, tmpBitmapSpace,
5131  table->write_set->n_bits, false);
5132  bitmap_copy(user_cols_written_bitmap, table->write_set);
5133 
5134  for (uint i= 0; i < table->s->fields; i++)
5135  {
5136  Field *field= table->field[i];
5137  DBUG_PRINT("info", ("Field#%u, (%u), Type : %u "
5138  "NO_DEFAULT_VALUE_FLAG : %u PRI_KEY_FLAG : %u",
5139  i,
5140  field->field_index,
5141  field->real_type(),
5142  field->flags & NO_DEFAULT_VALUE_FLAG,
5143  field->flags & PRI_KEY_FLAG));
5144  if ((field->flags & (NO_DEFAULT_VALUE_FLAG | // bug 41616
5145  PRI_KEY_FLAG)) || // bug 42238
5146  ! type_supports_default_value(field->real_type()))
5147  {
5148  bitmap_set_bit(user_cols_written_bitmap, field->field_index);
5149  }
5150  }
5151 
5152  mask= (uchar *)(user_cols_written_bitmap->bitmap);
5153  }
5154  else
5155  {
5156  /* No defaults in kernel, provide all columns ourselves */
5157  DBUG_PRINT("info", ("No native defaults, sending all values"));
5158  user_cols_written_bitmap= NULL;
5159  mask = NULL;
5160  }
5161 
5162  /* Using insert, we write all non default columns */
5163  op= trans->insertTuple(key_rec, (const char *)key_row, m_ndb_record,
5164  (char *)record, mask, // Default value should be masked
5165  poptions, sizeof(NdbOperation::OperationOptions));
5166  }
5167  if (!(op))
5168  ERR_RETURN(trans->getNdbError());
5169 
5170  bool do_batch= !need_flush &&
5171  (batched_update || thd_allow_batch(thd));
5172  uint blob_count= 0;
5173  if (table_share->blob_fields > 0)
5174  {
5175  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
5176  /* Set Blob values for all columns updated by the operation */
5177  int res= set_blob_values(op, record - table->record[0],
5178  user_cols_written_bitmap, &blob_count, do_batch);
5179  dbug_tmp_restore_column_map(table->read_set, old_map);
5180  if (res != 0)
5181  DBUG_RETURN(res);
5182  }
5183 
5184  m_rows_changed++;
5185 
5186  /*
5187  Execute write operation
5188  NOTE When doing inserts with many values in
5189  each INSERT statement it should not be necessary
5190  to NoCommit the transaction between each row.
5191  Find out how this is detected!
5192  */
5193  m_rows_inserted++;
5194  no_uncommitted_rows_update(1);
5195  if (( (m_rows_to_insert == 1 || uses_blobs) && !do_batch ) ||
5196  primary_key_update ||
5197  need_flush)
5198  {
5199  int res= flush_bulk_insert();
5200  if (res != 0)
5201  {
5202  m_skip_auto_increment= TRUE;
5203  DBUG_RETURN(res);
5204  }
5205  }
5206  if ((has_auto_increment) && (m_skip_auto_increment))
5207  {
5208  int ret_val;
5209  if ((ret_val= set_auto_inc(thd, table->next_number_field)))
5210  {
5211  DBUG_RETURN(ret_val);
5212  }
5213  }
5214  m_skip_auto_increment= TRUE;
5215 
5216  DBUG_PRINT("exit",("ok"));
5217  DBUG_RETURN(0);
5218 }
5219 
5220 
5221 /* Compare if an update changes the primary key in a row. */
5222 int ha_ndbcluster::primary_key_cmp(const uchar * old_row, const uchar * new_row)
5223 {
5224  uint keynr= table_share->primary_key;
5225  KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
5226  KEY_PART_INFO *end=key_part+table->key_info[keynr].user_defined_key_parts;
5227 
5228  for (; key_part != end ; key_part++)
5229  {
5230  if (!bitmap_is_set(table->write_set, key_part->fieldnr - 1))
5231  continue;
5232 
5233  /* The primary key does not allow NULLs. */
5234  DBUG_ASSERT(!key_part->null_bit);
5235 
5236  if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
5237  {
5238 
5239  if (key_part->field->cmp_binary((old_row + key_part->offset),
5240  (new_row + key_part->offset),
5241  (ulong) key_part->length))
5242  return 1;
5243  }
5244  else
5245  {
5246  if (memcmp(old_row+key_part->offset, new_row+key_part->offset,
5247  key_part->length))
5248  return 1;
5249  }
5250  }
5251  return 0;
5252 }
5253 
5254 #ifdef HAVE_NDB_BINLOG
5255 int
5256 handle_row_conflict(NDB_CONFLICT_FN_SHARE* cfn_share,
5257  const char* table_name,
5258  const NdbRecord* key_rec,
5259  const uchar* pk_row,
5260  enum_conflicting_op_type op_type,
5261  enum_conflict_cause conflict_cause,
5262  const NdbError& conflict_error,
5263  NdbTransaction* conflict_trans,
5264  NdbError& err)
5265 {
5266  DBUG_ENTER("handle_row_conflict");
5267 
5268  if (cfn_share->m_flags & CFF_REFRESH_ROWS)
5269  {
5270  /* A conflict has been detected between an applied replicated operation
5271  * and the data in the DB.
5272  * The attempt to change the local DB will have been rejected.
5273  * We now take steps to generate a refresh Binlog event so that
5274  * other clusters will be re-aligned.
5275  */
5276  DBUG_PRINT("info", ("Conflict on table %s. Operation type : %s, "
5277  "conflict cause :%s, conflict error : %u : %s",
5278  table_name,
5279  ((op_type == WRITE_ROW)? "WRITE_ROW":
5280  (op_type == UPDATE_ROW)? "UPDATE_ROW":
5281  "DELETE_ROW"),
5282  ((conflict_cause == ROW_ALREADY_EXISTS)?"ROW_ALREADY_EXISTS":
5283  (conflict_cause == ROW_DOES_NOT_EXIST)?"ROW_DOES_NOT_EXIST":
5284  "ROW_IN_CONFLICT"),
5285  conflict_error.code,
5286  conflict_error.message));
5287 
5288  assert(key_rec != NULL);
5289  assert(pk_row != NULL);
5290 
5291  /* When the slave splits an epoch into batches, a conflict row detected
5292  * and refreshed in an early batch can be written to by operations in
5293  * a later batch. As the operations will not have applied, and the
5294  * row has already been refreshed, we need not attempt to refresh
5295  * it again
5296  */
5297  if ((conflict_cause == ROW_IN_CONFLICT) &&
5298  (conflict_error.code == (int) error_op_after_refresh_op))
5299  {
5300  /* Attempt to apply an operation after the row was refreshed
5301  * Ignore the error
5302  */
5303  DBUG_PRINT("info", ("Operation after refresh error - ignoring"));
5304  DBUG_RETURN(0);
5305  }
5306 
5307  /* When a delete operation finds that the row does not exist, it indicates
5308  * a DELETE vs DELETE conflict. If we refresh the row then we can get
5309  * non deterministic behaviour depending on slave batching as follows :
5310  * Row is deleted
5311  *
5312  * Case 1
5313  * Slave applied DELETE, INSERT in 1 batch
5314  *
5315  * After first batch, the row is present (due to INSERT), it is
5316  * refreshed.
5317  *
5318  * Case 2
5319  * Slave applied DELETE in 1 batch, INSERT in 2nd batch
5320  *
5321  * After first batch, the row is not present, it is refreshed
5322  * INSERT is then rejected.
5323  *
5324  * The problem of not being able to 'record' a DELETE vs DELETE conflict
5325  * is known. We attempt at least to give consistent behaviour for
5326  * DELETE vs DELETE conflicts by :
5327  * NOT refreshing a row when a DELETE vs DELETE conflict is detected
5328  * This should map all batching scenarios onto Case1.
5329  */
5330  if ((op_type == DELETE_ROW) &&
5331  (conflict_cause == ROW_DOES_NOT_EXIST))
5332  {
5333  DBUG_PRINT("info", ("Delete vs Delete detected, NOT refreshing"));
5334  DBUG_RETURN(0);
5335  }
5336 
5337  /* Create a refresh to operation to realign other clusters */
5338  // TODO AnyValue
5339  // TODO Do we ever get non-PK key?
5340  // Keyless table?
5341  // Unique index
5342  const NdbOperation* refresh_op= conflict_trans->refreshTuple(key_rec,
5343  (const char*) pk_row);
5344 
5345  if (!refresh_op)
5346  {
5347  err= conflict_trans->getNdbError();
5348  DBUG_RETURN(1);
5349  }
5350  } /* if (cfn_share->m_flags & CFF_REFRESH_ROWS) */
5351 
5352  DBUG_RETURN(0);
5353 };
5354 #endif /* HAVE_NDB_BINLOG */
5355 
5361 {
5362  DBUG_ENTER("ha_ndbcluster::start_bulk_update");
5363  if (!m_use_write && m_ignore_dup_key)
5364  {
5365  DBUG_PRINT("info", ("Batching turned off as duplicate key is "
5366  "ignored by using peek_row"));
5367  DBUG_RETURN(TRUE);
5368  }
5369  DBUG_RETURN(FALSE);
5370 }
5371 
5372 int ha_ndbcluster::bulk_update_row(const uchar *old_data, uchar *new_data,
5373  uint *dup_key_found)
5374 {
5375  DBUG_ENTER("ha_ndbcluster::bulk_update_row");
5376  *dup_key_found= 0;
5377  DBUG_RETURN(ndb_update_row(old_data, new_data, 1));
5378 }
5379 
5380 int ha_ndbcluster::exec_bulk_update(uint *dup_key_found)
5381 {
5382  NdbTransaction* trans= m_thd_ndb->trans;
5383  DBUG_ENTER("ha_ndbcluster::exec_bulk_update");
5384  *dup_key_found= 0;
5385 
5386  // m_handler must be NULL or point to _this_ handler instance
5387  assert(m_thd_ndb->m_handler == NULL || m_thd_ndb->m_handler == this);
5388 
5389  if (m_thd_ndb->m_handler &&
5390  m_read_before_write_removal_possible)
5391  {
5392  /*
5393  This is an autocommit involving only one table and rbwr is on
5394 
5395  Commit the autocommit transaction early(before the usual place
5396  in ndbcluster_commit) in order to:
5397  1) save one round trip, "no-commit+commit" converted to "commit"
5398  2) return the correct number of updated and affected rows
5399  to the update loop(which will ask handler in rbwr mode)
5400  */
5401  DBUG_PRINT("info", ("committing auto-commit+rbwr early"));
5402  uint ignore_count= 0;
5403  const int ignore_error= 1;
5404  if (execute_commit(table->in_use, m_thd_ndb, trans,
5405  m_thd_ndb->m_force_send, ignore_error,
5406  &ignore_count) != 0)
5407  {
5408  no_uncommitted_rows_execute_failure();
5409  DBUG_RETURN(ndb_err(trans));
5410  }
5411  DBUG_PRINT("info", ("ignore_count: %u", ignore_count));
5412  assert(m_rows_changed >= ignore_count);
5413  assert(m_rows_updated >= ignore_count);
5414  m_rows_changed-= ignore_count;
5415  m_rows_updated-= ignore_count;
5416  DBUG_RETURN(0);
5417  }
5418 
5419  if (m_thd_ndb->m_unsent_bytes == 0)
5420  {
5421  DBUG_PRINT("exit", ("skip execute - no unsent bytes"));
5422  DBUG_RETURN(0);
5423  }
5424 
5425  if (thd_allow_batch(table->in_use))
5426  {
5427  /*
5428  Turned on by @@transaction_allow_batching=ON
5429  or implicitly by slave exec thread
5430  */
5431  DBUG_PRINT("exit", ("skip execute - transaction_allow_batching is ON"));
5432  DBUG_RETURN(0);
5433  }
5434 
5435  if (m_thd_ndb->m_handler &&
5436  !m_blobs_pending)
5437  {
5438  // Execute at commit time(in 'ndbcluster_commit') to save a round trip
5439  DBUG_PRINT("exit", ("skip execute - simple autocommit"));
5440  DBUG_RETURN(0);
5441  }
5442 
5443  uint ignore_count= 0;
5444  if (execute_no_commit(m_thd_ndb, trans,
5445  m_ignore_no_key || m_read_before_write_removal_used,
5446  &ignore_count) != 0)
5447  {
5448  no_uncommitted_rows_execute_failure();
5449  DBUG_RETURN(ndb_err(trans));
5450  }
5451  assert(m_rows_changed >= ignore_count);
5452  assert(m_rows_updated >= ignore_count);
5453  m_rows_changed-= ignore_count;
5454  m_rows_updated-= ignore_count;
5455  DBUG_RETURN(0);
5456 }
5457 
5459 {
5460  DBUG_ENTER("ha_ndbcluster::end_bulk_update");
5461  DBUG_VOID_RETURN;
5462 }
5463 
5464 int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data)
5465 {
5466  return ndb_update_row(old_data, new_data, 0);
5467 }
5468 
5469 void
5470 ha_ndbcluster::setup_key_ref_for_ndb_record(const NdbRecord **key_rec,
5471  const uchar **key_row,
5472  const uchar *record,
5473  bool use_active_index)
5474 {
5475  DBUG_ENTER("setup_key_ref_for_ndb_record");
5476  if (use_active_index)
5477  {
5478  /* Use unique key to access table */
5479  DBUG_PRINT("info", ("Using unique index (%u)", active_index));
5480  *key_rec= m_index[active_index].ndb_unique_record_row;
5481  *key_row= record;
5482  }
5483  else if (table_share->primary_key != MAX_KEY)
5484  {
5485  /* Use primary key to access table */
5486  DBUG_PRINT("info", ("Using primary key"));
5487  *key_rec= m_index[table_share->primary_key].ndb_unique_record_row;
5488  *key_row= record;
5489  }
5490  else
5491  {
5492  /* Use hidden primary key previously read into m_ref. */
5493  DBUG_PRINT("info", ("Using hidden primary key (%llu)", m_ref));
5494  /* Can't use hidden pk if we didn't read it first */
5495  DBUG_ASSERT(m_read_before_write_removal_used == false);
5496  *key_rec= m_ndb_hidden_key_record;
5497  *key_row= (const uchar *)(&m_ref);
5498  }
5499  DBUG_VOID_RETURN;
5500 }
5501 
5502 
5503 /*
5504  Update one record in NDB using primary key
5505 */
5506 
5507 int ha_ndbcluster::ndb_update_row(const uchar *old_data, uchar *new_data,
5508  int is_bulk_update)
5509 {
5510  THD *thd= table->in_use;
5511  Thd_ndb *thd_ndb= m_thd_ndb;
5512  NdbTransaction *trans= thd_ndb->trans;
5513  NdbScanOperation* cursor= m_active_cursor;
5514  const NdbOperation *op;
5515  uint32 old_part_id= ~uint32(0), new_part_id= ~uint32(0);
5516  int error;
5517  longlong func_value;
5518  Uint32 func_value_uint32;
5519  bool have_pk= (table_share->primary_key != MAX_KEY);
5520  bool pk_update= (!m_read_before_write_removal_possible &&
5521  have_pk &&
5522  bitmap_is_overlapping(table->write_set, m_pk_bitmap_p) &&
5523  primary_key_cmp(old_data, new_data));
5524  bool batch_allowed= !m_update_cannot_batch &&
5525  (is_bulk_update || thd_allow_batch(thd));
5527  Uint32 num_sets= 0;
5528 
5529  DBUG_ENTER("ndb_update_row");
5530  DBUG_ASSERT(trans);
5531 
5532  error = check_slave_state(thd);
5533  if (unlikely(error))
5534  DBUG_RETURN(error);
5535 
5536  /*
5537  * If IGNORE the ignore constraint violations on primary and unique keys,
5538  * but check that it is not part of INSERT ... ON DUPLICATE KEY UPDATE
5539  */
5540  if (m_ignore_dup_key && (thd->lex->sql_command == SQLCOM_UPDATE ||
5541  thd->lex->sql_command == SQLCOM_UPDATE_MULTI))
5542  {
5543  NDB_WRITE_OP write_op= (pk_update) ? NDB_PK_UPDATE : NDB_UPDATE;
5544  int peek_res= peek_indexed_rows(new_data, write_op);
5545 
5546  if (!peek_res)
5547  {
5548  DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
5549  }
5550  if (peek_res != HA_ERR_KEY_NOT_FOUND)
5551  DBUG_RETURN(peek_res);
5552  }
5553 
5554  ha_statistic_increment(&SSV::ha_update_count);
5555 
5556  bool skip_partition_for_unique_index= FALSE;
5557  if (m_use_partition_pruning)
5558  {
5559  if (!cursor && m_read_before_write_removal_used)
5560  {
5561  ndb_index_type type= get_index_type(active_index);
5562  /*
5563  Ndb unique indexes are global so when
5564  m_read_before_write_removal_used is active
5565  the unique index can be used directly for update
5566  without finding the partitions
5567  */
5568  if (type == UNIQUE_INDEX ||
5569  type == UNIQUE_ORDERED_INDEX)
5570  {
5571  skip_partition_for_unique_index= TRUE;
5572  goto skip_partition_pruning;
5573  }
5574  }
5575  if ((error= get_parts_for_update(old_data, new_data, table->record[0],
5576  m_part_info, &old_part_id, &new_part_id,
5577  &func_value)))
5578  {
5579  m_part_info->err_value= func_value;
5580  DBUG_RETURN(error);
5581  }
5582  DBUG_PRINT("info", ("old_part_id: %u new_part_id: %u", old_part_id, new_part_id));
5583  skip_partition_pruning:
5584  (void)0;
5585  }
5586 
5587  /*
5588  * Check for update of primary key or partition change
5589  * for special handling
5590  */
5591  if (pk_update || old_part_id != new_part_id)
5592  {
5593  DBUG_RETURN(ndb_pk_update_row(thd, old_data, new_data, old_part_id));
5594  }
5595  /*
5596  If we are updating a unique key with auto_increment
5597  then we need to update the auto_increment counter
5598  */
5599  if (table->found_next_number_field &&
5600  bitmap_is_set(table->write_set,
5601  table->found_next_number_field->field_index) &&
5602  (error= set_auto_inc(thd, table->found_next_number_field)))
5603  {
5604  DBUG_RETURN(error);
5605  }
5606  /*
5607  Set only non-primary-key attributes.
5608  We already checked that any primary key attribute in write_set has no
5609  real changes.
5610  */
5611  bitmap_copy(&m_bitmap, table->write_set);
5612  bitmap_subtract(&m_bitmap, m_pk_bitmap_p);
5613  uchar *mask= (uchar *)(m_bitmap.bitmap);
5614  DBUG_ASSERT(!pk_update);
5615 
5616  NdbOperation::OperationOptions *poptions = NULL;
5618  options.optionsPresent=0;
5619 
5620  /* Need to set the value of any user-defined partitioning function.
5621  (excecpt for when using unique index)
5622  */
5623  if (m_user_defined_partitioning && !skip_partition_for_unique_index)
5624  {
5625  if (func_value >= INT_MAX32)
5626  func_value_uint32= INT_MAX32;
5627  else
5628  func_value_uint32= (uint32)func_value;
5629  sets[num_sets].column= get_partition_id_column();
5630  sets[num_sets].value= &func_value_uint32;
5631  num_sets++;
5632 
5633  if (!cursor)
5634  {
5635  options.optionsPresent|= NdbOperation::OperationOptions::OO_PARTITION_ID;
5636  options.partitionId= new_part_id;
5637  }
5638  }
5639 
5640  eventSetAnyValue(thd, &options);
5641 
5642  bool need_flush= add_row_check_if_batch_full(thd_ndb);
5643 
5644  const Uint32 authorValue = 1;
5645  if ((thd->slave_thread) &&
5646  (m_table->getExtraRowAuthorBits()))
5647  {
5648  /* Set author to indicate slave updated last */
5649  sets[num_sets].column= NdbDictionary::Column::ROW_AUTHOR;
5650  sets[num_sets].value= &authorValue;
5651  num_sets++;
5652  }
5653 
5654  if (num_sets)
5655  {
5656  options.optionsPresent|= NdbOperation::OperationOptions::OO_SETVALUE;
5657  options.extraSetValues= sets;
5658  options.numExtraSetValues= num_sets;
5659  }
5660 
5661  if (thd->slave_thread || THDVAR(thd, deferred_constraints))
5662  {
5663  options.optionsPresent |=
5664  NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
5665  }
5666 
5667  if (cursor)
5668  {
5669  /*
5670  We are scanning records and want to update the record
5671  that was just found, call updateCurrentTuple on the cursor
5672  to take over the lock to a new update operation
5673  And thus setting the primary key of the record from
5674  the active record in cursor
5675  */
5676  DBUG_PRINT("info", ("Calling updateTuple on cursor, write_set=0x%x",
5677  table->write_set->bitmap[0]));
5678 
5679  if (options.optionsPresent != 0)
5680  poptions = &options;
5681 
5682  if (!(op= cursor->updateCurrentTuple(trans, m_ndb_record,
5683  (const char*)new_data, mask,
5684  poptions,
5686  ERR_RETURN(trans->getNdbError());
5687 
5688  m_lock_tuple= FALSE;
5689  thd_ndb->m_unsent_bytes+= 12;
5690  }
5691  else
5692  {
5693  const NdbRecord *key_rec;
5694  const uchar *key_row;
5695  setup_key_ref_for_ndb_record(&key_rec, &key_row, new_data,
5696  m_read_before_write_removal_used);
5697 
5698 #ifdef HAVE_NDB_BINLOG
5699  Uint32 buffer[ MAX_CONFLICT_INTERPRETED_PROG_SIZE ];
5700  NdbInterpretedCode code(m_table, buffer,
5701  sizeof(buffer)/sizeof(buffer[0]));
5702 
5703  if (thd->slave_thread && m_share->m_cfn_share &&
5704  m_share->m_cfn_share->m_conflict_fn)
5705  {
5706  /* Conflict resolution in slave thread. */
5707  if (unlikely((error = prepare_conflict_detection(UPDATE_ROW,
5708  key_rec,
5709  old_data,
5710  new_data,
5711  &code,
5712  &options))))
5713  DBUG_RETURN(error);
5714  }
5715 #endif /* HAVE_NDB_BINLOG */
5716  if (options.optionsPresent !=0)
5717  poptions= &options;
5718 
5719  if (!(op= trans->updateTuple(key_rec, (const char *)key_row,
5720  m_ndb_record, (const char*)new_data, mask,
5721  poptions,
5723  ERR_RETURN(trans->getNdbError());
5724  }
5725 
5726  uint blob_count= 0;
5727  if (uses_blob_value(table->write_set))
5728  {
5729  int row_offset= new_data - table->record[0];
5730  int res= set_blob_values(op, row_offset, table->write_set, &blob_count,
5731  (batch_allowed && !need_flush));
5732  if (res != 0)
5733  DBUG_RETURN(res);
5734  }
5735  uint ignore_count= 0;
5736  /*
5737  Batch update operation if we are doing a scan for update, unless
5738  there exist UPDATE AFTER triggers
5739  */
5740  if (m_update_cannot_batch ||
5741  !(cursor || (batch_allowed && have_pk)) ||
5742  need_flush)
5743  {
5744  if (execute_no_commit(m_thd_ndb, trans,
5745  m_ignore_no_key || m_read_before_write_removal_used,
5746  &ignore_count) != 0)
5747  {
5748  no_uncommitted_rows_execute_failure();
5749  DBUG_RETURN(ndb_err(trans));
5750  }
5751  }
5752  else if (blob_count > 0)
5753  m_blobs_pending= TRUE;
5754 
5755  m_rows_changed++;
5756  m_rows_updated++;
5757 
5758  assert(m_rows_changed >= ignore_count);
5759  assert(m_rows_updated >= ignore_count);
5760  m_rows_changed-= ignore_count;
5761  m_rows_updated-= ignore_count;
5762 
5763  DBUG_RETURN(0);
5764 }
5765 
5766 
5767 /*
5768  handler delete interface
5769 */
5770 
5771 int ha_ndbcluster::delete_row(const uchar *record)
5772 {
5773  return ndb_delete_row(record, FALSE);
5774 }
5775 
5776 bool ha_ndbcluster::start_bulk_delete()
5777 {
5778  DBUG_ENTER("start_bulk_delete");
5779  m_is_bulk_delete = true;
5780  DBUG_RETURN(0); // Bulk delete used by handler
5781 }
5782 
5783 int ha_ndbcluster::end_bulk_delete()
5784 {
5785  NdbTransaction* trans= m_thd_ndb->trans;
5786  DBUG_ENTER("end_bulk_delete");
5787  assert(m_is_bulk_delete); // Don't allow end() without start()
5788  m_is_bulk_delete = false;
5789 
5790  // m_handler must be NULL or point to _this_ handler instance
5791  assert(m_thd_ndb->m_handler == NULL || m_thd_ndb->m_handler == this);
5792 
5793  if (m_thd_ndb->m_handler &&
5794  m_read_before_write_removal_possible)
5795  {
5796  /*
5797  This is an autocommit involving only one table and rbwr is on
5798 
5799  Commit the autocommit transaction early(before the usual place
5800  in ndbcluster_commit) in order to:
5801  1) save one round trip, "no-commit+commit" converted to "commit"
5802  2) return the correct number of updated and affected rows
5803  to the delete loop(which will ask handler in rbwr mode)
5804  */
5805  DBUG_PRINT("info", ("committing auto-commit+rbwr early"));
5806  uint ignore_count= 0;
5807  const int ignore_error= 1;
5808  if (execute_commit(table->in_use, m_thd_ndb, trans,
5809  m_thd_ndb->m_force_send, ignore_error,
5810  &ignore_count) != 0)
5811  {
5812  no_uncommitted_rows_execute_failure();
5813  DBUG_RETURN(ndb_err(trans));
5814  }
5815  DBUG_PRINT("info", ("ignore_count: %u", ignore_count));
5816  assert(m_rows_deleted >= ignore_count);
5817  m_rows_deleted-= ignore_count;
5818  DBUG_RETURN(0);
5819  }
5820 
5821  if (m_thd_ndb->m_unsent_bytes == 0)
5822  {
5823  DBUG_PRINT("exit", ("skip execute - no unsent bytes"));
5824  DBUG_RETURN(0);
5825  }
5826 
5827  if (thd_allow_batch(table->in_use))
5828  {
5829  /*
5830  Turned on by @@transaction_allow_batching=ON
5831  or implicitly by slave exec thread
5832  */
5833  DBUG_PRINT("exit", ("skip execute - transaction_allow_batching is ON"));
5834  DBUG_RETURN(0);
5835  }
5836 
5837  if (m_thd_ndb->m_handler)
5838  {
5839  // Execute at commit time(in 'ndbcluster_commit') to save a round trip
5840  DBUG_PRINT("exit", ("skip execute - simple autocommit"));
5841  DBUG_RETURN(0);
5842  }
5843 
5844  uint ignore_count= 0;
5845  if (execute_no_commit(m_thd_ndb, trans,
5846  m_ignore_no_key || m_read_before_write_removal_used,
5847  &ignore_count) != 0)
5848  {
5849  no_uncommitted_rows_execute_failure();
5850  DBUG_RETURN(ndb_err(trans));
5851  }
5852 
5853  assert(m_rows_deleted >= ignore_count);
5854  m_rows_deleted-= ignore_count;
5855  no_uncommitted_rows_update(ignore_count);
5856  DBUG_RETURN(0);
5857 }
5858 
5859 
5864 int ha_ndbcluster::ndb_delete_row(const uchar *record,
5865  bool primary_key_update)
5866 {
5867  THD *thd= table->in_use;
5868  Thd_ndb *thd_ndb= get_thd_ndb(thd);
5869  NdbTransaction *trans= m_thd_ndb->trans;
5870  NdbScanOperation* cursor= m_active_cursor;
5871  const NdbOperation *op;
5872  uint32 part_id= ~uint32(0);
5873  int error;
5874  bool allow_batch= !m_delete_cannot_batch &&
5875  (m_is_bulk_delete || thd_allow_batch(thd));
5876 
5877  DBUG_ENTER("ndb_delete_row");
5878  DBUG_ASSERT(trans);
5879 
5880  error = check_slave_state(thd);
5881  if (unlikely(error))
5882  DBUG_RETURN(error);
5883 
5884  ha_statistic_increment(&SSV::ha_delete_count);
5885  m_rows_changed++;
5886 
5887  bool skip_partition_for_unique_index= FALSE;
5888  if (m_use_partition_pruning)
5889  {
5890  if (!cursor && m_read_before_write_removal_used)
5891  {
5892  ndb_index_type type= get_index_type(active_index);
5893  /*
5894  Ndb unique indexes are global so when
5895  m_read_before_write_removal_used is active
5896  the unique index can be used directly for deleting
5897  without finding the partitions
5898  */
5899  if (type == UNIQUE_INDEX ||
5900  type == UNIQUE_ORDERED_INDEX)
5901  {
5902  skip_partition_for_unique_index= TRUE;
5903  goto skip_partition_pruning;
5904  }
5905  }
5906  if ((error= get_part_for_delete(record, table->record[0], m_part_info,
5907  &part_id)))
5908  {
5909  DBUG_RETURN(error);
5910  }
5911  skip_partition_pruning:
5912  (void)0;
5913  }
5914 
5916  NdbOperation::OperationOptions *poptions = NULL;
5917  options.optionsPresent=0;
5918 
5919  eventSetAnyValue(thd, &options);
5920 
5921  /*
5922  Poor approx. let delete ~ tabsize / 4
5923  */
5924  uint delete_size= 12 + (m_bytes_per_write >> 2);
5925  bool need_flush= add_row_check_if_batch_full_size(thd_ndb, delete_size);
5926 
5927  if (thd->slave_thread || THDVAR(thd, deferred_constraints))
5928  {
5929  options.optionsPresent |=
5930  NdbOperation::OperationOptions::OO_DEFERRED_CONSTAINTS;
5931  }
5932 
5933  if (cursor)
5934  {
5935  if (options.optionsPresent != 0)
5936  poptions = &options;
5937 
5938  /*
5939  We are scanning records and want to delete the record
5940  that was just found, call deleteTuple on the cursor
5941  to take over the lock to a new delete operation
5942  And thus setting the primary key of the record from
5943  the active record in cursor
5944  */
5945  DBUG_PRINT("info", ("Calling deleteTuple on cursor"));
5946  if ((op = cursor->deleteCurrentTuple(trans, m_ndb_record,
5947  NULL, // result_row
5948  NULL, // result_mask
5949  poptions,
5950  sizeof(NdbOperation::OperationOptions))) == 0)
5951  ERR_RETURN(trans->getNdbError());
5952  m_lock_tuple= FALSE;
5953  thd_ndb->m_unsent_bytes+= 12;
5954 
5955  no_uncommitted_rows_update(-1);
5956  m_rows_deleted++;
5957 
5958  if (!(primary_key_update || m_delete_cannot_batch))
5959  {
5960  // If deleting from cursor, NoCommit will be handled in next_result
5961  DBUG_RETURN(0);
5962  }
5963  }
5964  else
5965  {
5966  const NdbRecord *key_rec;
5967  const uchar *key_row;
5968 
5969  if (m_user_defined_partitioning && !skip_partition_for_unique_index)
5970  {
5971  options.optionsPresent|= NdbOperation::OperationOptions::OO_PARTITION_ID;
5972  options.partitionId= part_id;
5973  }
5974 
5975  setup_key_ref_for_ndb_record(&key_rec, &key_row, record,
5976  m_read_before_write_removal_used);
5977 
5978 #ifdef HAVE_NDB_BINLOG
5979  Uint32 buffer[ MAX_CONFLICT_INTERPRETED_PROG_SIZE ];
5980  NdbInterpretedCode code(m_table, buffer,
5981  sizeof(buffer)/sizeof(buffer[0]));
5982  if (thd->slave_thread && m_share->m_cfn_share &&
5983  m_share->m_cfn_share->m_conflict_fn)
5984  {
5985  /* Conflict resolution in slave thread. */
5986  if (unlikely((error = prepare_conflict_detection(DELETE_ROW,
5987  key_rec,
5988  key_row, /* old_data */
5989  NULL, /* new_data */
5990  &code,
5991  &options))))
5992  DBUG_RETURN(error);
5993  }
5994 #endif /* HAVE_NDB_BINLOG */
5995  if (options.optionsPresent != 0)
5996  poptions= &options;
5997 
5998  if (!(op=trans->deleteTuple(key_rec, (const char *)key_row,
5999  m_ndb_record,
6000  NULL, // row
6001  NULL, // mask
6002  poptions,
6004  ERR_RETURN(trans->getNdbError());
6005 
6006  no_uncommitted_rows_update(-1);
6007  m_rows_deleted++;
6008 
6009  /*
6010  Check if we can batch the delete.
6011 
6012  We don't batch deletes as part of primary key updates.
6013  We do not batch deletes on tables with no primary key. For such tables,
6014  replication uses full table scan to locate the row to delete. The
6015  problem is the following scenario when deleting 2 (or more) rows:
6016 
6017  1. Table scan to locate the first row.
6018  2. Delete the row, batched so no execute.
6019  3. Table scan to locate the second row is executed, along with the
6020  batched delete operation from step 2.
6021  4. The first row is returned from nextResult() (not deleted yet).
6022  5. The kernel deletes the row (operation from step 2).
6023  6. lockCurrentTuple() is called on the row returned in step 4. However,
6024  as that row is now deleted, the operation fails and the transaction
6025  is aborted.
6026  7. The delete of the second tuple now fails, as the transaction has
6027  been aborted.
6028  */
6029 
6030  if ( allow_batch &&
6031  table_share->primary_key != MAX_KEY &&
6032  !primary_key_update &&
6033  !need_flush)
6034  {
6035  DBUG_RETURN(0);
6036  }
6037  }
6038 
6039  // Execute delete operation
6040  uint ignore_count= 0;
6041  if (execute_no_commit(m_thd_ndb, trans,
6042  m_ignore_no_key || m_read_before_write_removal_used,
6043  &ignore_count) != 0)
6044  {
6045  no_uncommitted_rows_execute_failure();
6046  DBUG_RETURN(ndb_err(trans));
6047  }
6048  if (!primary_key_update)
6049  {
6050  assert(m_rows_deleted >= ignore_count);
6051  m_rows_deleted-= ignore_count;
6052  no_uncommitted_rows_update(ignore_count);
6053  }
6054  DBUG_RETURN(0);
6055 }
6056 
6065 void ha_ndbcluster::unpack_record(uchar *dst_row, const uchar *src_row)
6066 {
6067  int res;
6068  DBUG_ASSERT(src_row != NULL);
6069 
6070  my_ptrdiff_t dst_offset= dst_row - table->record[0];
6071  my_ptrdiff_t src_offset= src_row - table->record[0];
6072 
6073  /* Initialize the NULL bitmap. */
6074  memset(dst_row, 0xff, table->s->null_bytes);
6075 
6076  uchar *blob_ptr= m_blobs_buffer;
6077 
6078  for (uint i= 0; i < table_share->fields; i++)
6079  {
6080  Field *field= table->field[i];
6081  if (bitmap_is_set(table->read_set, i))
6082  {
6083  if (field->type() == MYSQL_TYPE_BIT)
6084  {
6085  Field_bit *field_bit= static_cast<Field_bit*>(field);
6086  if (!field->is_real_null(src_offset))
6087  {
6088  field->move_field_offset(src_offset);
6089  longlong value= field_bit->val_int();
6090  field->move_field_offset(dst_offset-src_offset);
6091  field_bit->set_notnull();
6092  /* Field_bit in DBUG requires the bit set in write_set for store(). */
6093  my_bitmap_map *old_map=
6094  dbug_tmp_use_all_columns(table, table->write_set);
6095  int res = field_bit->store(value, true);
6096  assert(res == 0); NDB_IGNORE_VALUE(res);
6097  dbug_tmp_restore_column_map(table->write_set, old_map);
6098  field->move_field_offset(-dst_offset);
6099  }
6100  }
6101  else if (field->flags & BLOB_FLAG)
6102  {
6103  Field_blob *field_blob= (Field_blob *)field;
6104  NdbBlob *ndb_blob= m_value[i].blob;
6105  /* unpack_record *only* called for scan result processing
6106  * *while* the scan is open and the Blob is active.
6107  * Verify Blob state to be certain.
6108  * Accessing PK/UK op Blobs after execute() is unsafe
6109  */
6110  DBUG_ASSERT(ndb_blob != 0);
6111  DBUG_ASSERT(ndb_blob->getState() == NdbBlob::Active);
6112  int isNull;
6113  res= ndb_blob->getNull(isNull);
6114  DBUG_ASSERT(res == 0); // Already succeeded once
6115  Uint64 len64= 0;
6116  field_blob->move_field_offset(dst_offset);
6117  if (!isNull)
6118  {
6119  res= ndb_blob->getLength(len64);
6120  DBUG_ASSERT(res == 0 && len64 <= (Uint64)0xffffffff);
6121  field->set_notnull();
6122  }
6123  /* Need not set_null(), as we initialized null bits to 1 above. */
6124  field_blob->set_ptr((uint32)len64, blob_ptr);
6125  field_blob->move_field_offset(-dst_offset);
6126  blob_ptr+= (len64 + 7) & ~((Uint64)7);
6127  }
6128  else
6129  {
6130  field->move_field_offset(src_offset);
6131  /* Normal field (not blob or bit type). */
6132  if (!field->is_null())
6133  {
6134  /* Only copy actually used bytes of varstrings. */
6135  uint32 actual_length= field_used_length(field);
6136  uchar *src_ptr= field->ptr;
6137  field->move_field_offset(dst_offset - src_offset);
6138  field->set_notnull();
6139  memcpy(field->ptr, src_ptr, actual_length);
6140 #ifdef HAVE_purify
6141  /*
6142  We get Valgrind warnings on uninitialised padding bytes in
6143  varstrings, for example when writing rows to temporary tables.
6144  So for valgrind builds we pad with zeros, not needed for
6145  production code.
6146  */
6147  if (actual_length < field->pack_length())
6148  memset(field->ptr + actual_length, 0,
6149  field->pack_length() - actual_length);
6150 #endif
6151  field->move_field_offset(-dst_offset);
6152  }
6153  else
6154  field->move_field_offset(-src_offset);
6155  /* No action needed for a NULL field. */
6156  }
6157  }
6158  }
6159 }
6160 
6161 
6165 static void get_default_value(void *def_val, Field *field)
6166 {
6167  DBUG_ASSERT(field != NULL);
6168 
6169  my_ptrdiff_t src_offset= field->table->s->default_values - field->table->record[0];
6170 
6171  {
6172  if (bitmap_is_set(field->table->read_set, field->field_index))
6173  {
6174  if (field->type() == MYSQL_TYPE_BIT)
6175  {
6176  Field_bit *field_bit= static_cast<Field_bit*>(field);
6177  if (!field->is_real_null(src_offset))
6178  {
6179  field->move_field_offset(src_offset);
6180  longlong value= field_bit->val_int();
6181  /* Map to NdbApi format - two Uint32s */
6182  Uint32 out[2];
6183  out[0] = 0;
6184  out[1] = 0;
6185  for (int b=0; b < 64; b++)
6186  {
6187  out[b >> 5] |= (value & 1) << (b & 31);
6188 
6189  value= value >> 1;
6190  }
6191  memcpy(def_val, out, sizeof(longlong));
6192  field->move_field_offset(-src_offset);
6193  }
6194  }
6195  else if (field->flags & BLOB_FLAG)
6196  {
6197  assert(false);
6198  }
6199  else
6200  {
6201  field->move_field_offset(src_offset);
6202  /* Normal field (not blob or bit type). */
6203  if (!field->is_null())
6204  {
6205  /* Only copy actually used bytes of varstrings. */
6206  uint32 actual_length= field_used_length(field);
6207  uchar *src_ptr= field->ptr;
6208  field->set_notnull();
6209  memcpy(def_val, src_ptr, actual_length);
6210 #ifdef HAVE_purify
6211  if (actual_length < field->pack_length())
6212  memset(((char*)def_val) + actual_length, 0,
6213  field->pack_length() - actual_length);
6214 #endif
6215  }
6216  field->move_field_offset(-src_offset);
6217  /* No action needed for a NULL field. */
6218  }
6219  }
6220  }
6221 }
6222 
6223 /*
6224  DBUG_EXECUTE("value", print_results(););
6225 */
6226 
6227 void ha_ndbcluster::print_results()
6228 {
6229  DBUG_ENTER("print_results");
6230 
6231 #ifndef DBUG_OFF
6232 
6233  char buf_type[MAX_FIELD_WIDTH], buf_val[MAX_FIELD_WIDTH];
6234  String type(buf_type, sizeof(buf_type), &my_charset_bin);
6235  String val(buf_val, sizeof(buf_val), &my_charset_bin);
6236  for (uint f= 0; f < table_share->fields; f++)
6237  {
6238  /* Use DBUG_PRINT since DBUG_FILE cannot be filtered out */
6239  char buf[2000];
6240  Field *field;
6241  void* ptr;
6242  NdbValue value;
6243 
6244  buf[0]= 0;
6245  field= table->field[f];
6246  if (!(value= m_value[f]).ptr)
6247  {
6248  strmov(buf, "not read");
6249  goto print_value;
6250  }
6251 
6252  ptr= field->ptr;
6253 
6254  if (! (field->flags & BLOB_FLAG))
6255  {
6256  if (value.rec->isNULL())
6257  {
6258  strmov(buf, "NULL");
6259  goto print_value;
6260  }
6261  type.length(0);
6262  val.length(0);
6263  field->sql_type(type);
6264  field->val_str(&val);
6265  my_snprintf(buf, sizeof(buf), "%s %s", type.c_ptr(), val.c_ptr());
6266  }
6267  else
6268  {
6269  NdbBlob *ndb_blob= value.blob;
6270  bool isNull= TRUE;
6271  assert(ndb_blob->getState() == NdbBlob::Active);
6272  ndb_blob->getNull(isNull);
6273  if (isNull)
6274  strmov(buf, "NULL");
6275  }
6276 
6277 print_value:
6278  DBUG_PRINT("value", ("%u,%s: %s", f, field->field_name, buf));
6279  }
6280 #endif
6281  DBUG_VOID_RETURN;
6282 }
6283 
6284 
6285 /*
6286  Set fields in partition functions in read set for underlying handlers
6287 
6288  SYNOPSIS
6289  include_partition_fields_in_used_fields()
6290 
6291  RETURN VALUE
6292  NONE
6293 
6294  DESCRIPTION
6295  Some handlers only read fields as specified by the bitmap for the
6296  read set. For partitioned handlers we always require that the
6297  fields of the partition functions are read such that we can
6298  calculate the partition id to place updated and deleted records.
6299 */
6300 
6301 static void
6302 include_partition_fields_in_used_fields(Field **ptr, MY_BITMAP *read_set)
6303 {
6304  DBUG_ENTER("include_partition_fields_in_used_fields");
6305  do
6306  {
6307  bitmap_set_bit(read_set, (*ptr)->field_index);
6308  } while (*(++ptr));
6309  DBUG_VOID_RETURN;
6310 }
6311 
6312 
6313 int ha_ndbcluster::index_init(uint index, bool sorted)
6314 {
6315  DBUG_ENTER("ha_ndbcluster::index_init");
6316  DBUG_PRINT("enter", ("index: %u sorted: %d", index, sorted));
6317  active_index= index;
6318  m_sorted= sorted;
6319  /*
6320  Locks are are explicitly released in scan
6321  unless m_lock.type == TL_READ_HIGH_PRIORITY
6322  and no sub-sequent call to unlock_row()
6323  */
6324  m_lock_tuple= FALSE;
6325  if (table_share->primary_key == MAX_KEY &&
6326  m_use_partition_pruning)
6327  include_partition_fields_in_used_fields(
6328  m_part_info->full_part_field_array,
6329  table->read_set);
6330  DBUG_RETURN(0);
6331 }
6332 
6333 
6334 int ha_ndbcluster::index_end()
6335 {
6336  DBUG_ENTER("ha_ndbcluster::index_end");
6337  DBUG_RETURN(close_scan());
6338 }
6339 
6343 static
6344 int
6345 check_null_in_key(const KEY* key_info, const uchar *key, uint key_len)
6346 {
6347  KEY_PART_INFO *curr_part, *end_part;
6348  const uchar* end_ptr= key + key_len;
6349  curr_part= key_info->key_part;
6350  end_part= curr_part + key_info->user_defined_key_parts;
6351 
6352  for (; curr_part != end_part && key < end_ptr; curr_part++)
6353  {
6354  if (curr_part->null_bit && *key)
6355  return 1;
6356 
6357  key += curr_part->store_length;
6358  }
6359  return 0;
6360 }
6361 
6362 
6363 int ha_ndbcluster::index_read_idx_map(uchar* buf, uint index,
6364  const uchar* key,
6365  key_part_map keypart_map,
6366  enum ha_rkey_function find_flag)
6367 {
6368  DBUG_ENTER("ha_ndbcluster::index_read_idx_map");
6369  int error= index_init(index, 0);
6370  if (unlikely(error))
6371  DBUG_RETURN(error);
6372 
6373  DBUG_RETURN(index_read_map(buf, key, keypart_map, find_flag));
6374 }
6375 
6376 
6377 int ha_ndbcluster::index_read(uchar *buf,
6378  const uchar *key, uint key_len,
6379  enum ha_rkey_function find_flag)
6380 {
6381  key_range start_key;
6382  bool descending= FALSE;
6383  DBUG_ENTER("ha_ndbcluster::index_read");
6384  DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d",
6385  active_index, key_len, find_flag));
6386 
6387  start_key.key= key;
6388  start_key.length= key_len;
6389  start_key.flag= find_flag;
6390  descending= FALSE;
6391  switch (find_flag) {
6392  case HA_READ_KEY_OR_PREV:
6393  case HA_READ_BEFORE_KEY:
6394  case HA_READ_PREFIX_LAST:
6395  case HA_READ_PREFIX_LAST_OR_PREV:
6396  descending= TRUE;
6397  break;
6398  default:
6399  break;
6400  }
6401  const int error= read_range_first_to_buf(&start_key, 0, descending,
6402  m_sorted, buf);
6403  table->status=error ? STATUS_NOT_FOUND: 0;
6404  DBUG_RETURN(error);
6405 }
6406 
6407 
6408 int ha_ndbcluster::index_next(uchar *buf)
6409 {
6410  DBUG_ENTER("ha_ndbcluster::index_next");
6411  ha_statistic_increment(&SSV::ha_read_next_count);
6412  const int error= next_result(buf);
6413  table->status=error ? STATUS_NOT_FOUND: 0;
6414  DBUG_RETURN(error);
6415 }
6416 
6417 
6418 int ha_ndbcluster::index_prev(uchar *buf)
6419 {
6420  DBUG_ENTER("ha_ndbcluster::index_prev");
6421  ha_statistic_increment(&SSV::ha_read_prev_count);
6422  const int error= next_result(buf);
6423  table->status=error ? STATUS_NOT_FOUND: 0;
6424  DBUG_RETURN(error);
6425 }
6426 
6427 
6428 int ha_ndbcluster::index_first(uchar *buf)
6429 {
6430  DBUG_ENTER("ha_ndbcluster::index_first");
6431  ha_statistic_increment(&SSV::ha_read_first_count);
6432  // Start the ordered index scan and fetch the first row
6433 
6434  // Only HA_READ_ORDER indexes get called by index_first
6435  const int error= ordered_index_scan(0, 0, m_sorted, FALSE, buf, NULL);
6436  table->status=error ? STATUS_NOT_FOUND: 0;
6437  DBUG_RETURN(error);
6438 }
6439 
6440 
6441 int ha_ndbcluster::index_last(uchar *buf)
6442 {
6443  DBUG_ENTER("ha_ndbcluster::index_last");
6444  ha_statistic_increment(&SSV::ha_read_last_count);
6445  const int error= ordered_index_scan(0, 0, m_sorted, TRUE, buf, NULL);
6446  table->status=error ? STATUS_NOT_FOUND: 0;
6447  DBUG_RETURN(error);
6448 }
6449 
6450 int ha_ndbcluster::index_read_last(uchar * buf, const uchar * key, uint key_len)
6451 {
6452  DBUG_ENTER("ha_ndbcluster::index_read_last");
6453  DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));
6454 }
6455 
6456 
6469 int ha_ndbcluster::read_first_row(uchar * buf, uint primary_key)
6470 {
6471  register int error;
6472  DBUG_ENTER("ha_ndbcluster::read_first_row");
6473 
6474  ha_statistic_increment(&SSV::ha_read_first_count);
6475 
6476  /*
6477  If there is very few deleted rows in the table, find the first row by
6478  scanning the table.
6479  TODO remove the test for HA_READ_ORDER
6480  */
6481  if (stats.deleted < 10 || primary_key >= MAX_KEY ||
6482  !(index_flags(primary_key, 0, 0) & HA_READ_ORDER))
6483  {
6484  (void) ha_rnd_init(1);
6485  while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ;
6486  }
6487  else
6488  {
6489  /* Find the first row through the primary key */
6490  (void) ha_index_init(primary_key, 0);
6491  error=index_first(buf);
6492  }
6493  DBUG_RETURN(error);
6494 }
6495 
6496 
6497 int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
6498  const key_range *end_key,
6499  bool desc, bool sorted,
6500  uchar* buf)
6501 {
6502  part_id_range part_spec;
6503  ndb_index_type type= get_index_type(active_index);
6504  const KEY* key_info= table->key_info+active_index;
6505  int error;
6506  DBUG_ENTER("ha_ndbcluster::read_range_first_to_buf");
6507  DBUG_PRINT("info", ("desc: %d, sorted: %d", desc, sorted));
6508 
6509  if (unlikely((error= close_scan())))
6510  DBUG_RETURN(error);
6511 
6512  if (m_use_partition_pruning)
6513  {
6514  DBUG_ASSERT(m_pushed_join_operation != PUSHED_ROOT);
6515  get_partition_set(table, buf, active_index, start_key, &part_spec);
6516  DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
6517  part_spec.start_part, part_spec.end_part));
6518  /*
6519  If partition pruning has found no partition in set
6520  we can return HA_ERR_END_OF_FILE
6521  If partition pruning has found exactly one partition in set
6522  we can optimize scan to run towards that partition only.
6523  */
6524  if (part_spec.start_part > part_spec.end_part)
6525  {
6526  DBUG_RETURN(HA_ERR_END_OF_FILE);
6527  }
6528 
6529  if (part_spec.start_part == part_spec.end_part)
6530  {
6531  /*
6532  Only one partition is required to scan, if sorted is required we
6533  don't need it any more since output from one ordered partitioned
6534  index is always sorted.
6535  */
6536  sorted= FALSE;
6537  if (unlikely(!get_transaction_part_id(part_spec.start_part, error)))
6538  {
6539  DBUG_RETURN(error);
6540  }
6541  }
6542  }
6543 
6544  switch (type){
6545  case PRIMARY_KEY_ORDERED_INDEX:
6546  case PRIMARY_KEY_INDEX:
6547  if (start_key &&
6548  start_key->length == key_info->key_length &&
6549  start_key->flag == HA_READ_KEY_EXACT)
6550  {
6551  if (!m_thd_ndb->trans)
6552  if (unlikely(!start_transaction_key(active_index,
6553  start_key->key, error)))
6554  DBUG_RETURN(error);
6555  error= pk_read(start_key->key, start_key->length, buf,
6556  (m_use_partition_pruning)? &(part_spec.start_part) : NULL);
6557  DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
6558  }
6559  break;
6560  case UNIQUE_ORDERED_INDEX:
6561  case UNIQUE_INDEX:
6562  if (start_key && start_key->length == key_info->key_length &&
6563  start_key->flag == HA_READ_KEY_EXACT &&
6564  !check_null_in_key(key_info, start_key->key, start_key->length))
6565  {
6566  if (!m_thd_ndb->trans)
6567  if (unlikely(!start_transaction_key(active_index,
6568  start_key->key, error)))
6569  DBUG_RETURN(error);
6570  error= unique_index_read(start_key->key, start_key->length, buf);
6571  DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
6572  }
6573  else if (type == UNIQUE_INDEX)
6574  DBUG_RETURN(full_table_scan(key_info,
6575  start_key,
6576  end_key,
6577  buf));
6578  break;
6579  default:
6580  break;
6581  }
6582  if (!m_use_partition_pruning && !m_thd_ndb->trans)
6583  {
6584  get_partition_set(table, buf, active_index, start_key, &part_spec);
6585  if (part_spec.start_part == part_spec.end_part)
6586  if (unlikely(!start_transaction_part_id(part_spec.start_part, error)))
6587  DBUG_RETURN(error);
6588  }
6589  // Start the ordered index scan and fetch the first row
6590  DBUG_RETURN(ordered_index_scan(start_key, end_key, sorted, desc, buf,
6591  (m_use_partition_pruning)? &part_spec : NULL));
6592 }
6593 
6594 int ha_ndbcluster::read_range_first(const key_range *start_key,
6595  const key_range *end_key,
6596  bool eq_r, bool sorted)
6597 {
6598  uchar* buf= table->record[0];
6599  DBUG_ENTER("ha_ndbcluster::read_range_first");
6600  DBUG_RETURN(read_range_first_to_buf(start_key, end_key, FALSE,
6601  sorted, buf));
6602 }
6603 
6605 {
6606  DBUG_ENTER("ha_ndbcluster::read_range_next");
6607  DBUG_RETURN(next_result(table->record[0]));
6608 }
6609 
6610 
6611 int ha_ndbcluster::rnd_init(bool scan)
6612 {
6613  int error;
6614  DBUG_ENTER("rnd_init");
6615  DBUG_PRINT("enter", ("scan: %d", scan));
6616 
6617  if ((error= close_scan()))
6618  DBUG_RETURN(error);
6619  index_init(table_share->primary_key, 0);
6620  DBUG_RETURN(0);
6621 }
6622 
6623 int ha_ndbcluster::close_scan()
6624 {
6625  /*
6626  workaround for bug #39872 - explain causes segv
6627  - rnd_end/close_scan is called on unlocked table
6628  - should be fixed in server code, but this will
6629  not be done until 6.0 as it is too intrusive
6630  */
6631  if (m_thd_ndb == NULL)
6632  return 0;
6633  NdbTransaction *trans= m_thd_ndb->trans;
6634  int error;
6635  DBUG_ENTER("close_scan");
6636 
6637  if (m_active_query)
6638  {
6639  m_active_query->close(m_thd_ndb->m_force_send);
6640  m_active_query= NULL;
6641  }
6642 
6643  NdbScanOperation *cursor= m_active_cursor;
6644 
6645  if (!cursor)
6646  {
6647  cursor = m_multi_cursor;
6648  if (!cursor)
6649  DBUG_RETURN(0);
6650  }
6651 
6652  if ((error= scan_handle_lock_tuple(cursor, trans)) != 0)
6653  DBUG_RETURN(error);
6654 
6655  if (m_thd_ndb->m_unsent_bytes)
6656  {
6657  /*
6658  Take over any pending transactions to the
6659  deleteing/updating transaction before closing the scan
6660  */
6661  DBUG_PRINT("info", ("thd_ndb->m_unsent_bytes: %ld",
6662  (long) m_thd_ndb->m_unsent_bytes));
6663  if (execute_no_commit(m_thd_ndb, trans, m_ignore_no_key) != 0)
6664  {
6665  no_uncommitted_rows_execute_failure();
6666  DBUG_RETURN(ndb_err(trans));
6667  }
6668  }
6669 
6670  cursor->close(m_thd_ndb->m_force_send, TRUE);
6671  m_active_cursor= NULL;
6672  m_multi_cursor= NULL;
6673  DBUG_RETURN(0);
6674 }
6675 
6676 int ha_ndbcluster::rnd_end()
6677 {
6678  DBUG_ENTER("rnd_end");
6679  DBUG_RETURN(close_scan());
6680 }
6681 
6682 
6683 int ha_ndbcluster::rnd_next(uchar *buf)
6684 {
6685  DBUG_ENTER("rnd_next");
6686  ha_statistic_increment(&SSV::ha_read_rnd_next_count);
6687 
6688  int error;
6689  if (m_active_cursor)
6690  error= next_result(buf);
6691  else if (m_active_query)
6692  error= next_result(buf);
6693  else
6694  error= full_table_scan(NULL, NULL, NULL, buf);
6695 
6696  table->status= error ? STATUS_NOT_FOUND: 0;
6697  DBUG_RETURN(error);
6698 }
6699 
6700 
6707 int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos)
6708 {
6709  DBUG_ENTER("rnd_pos");
6710  ha_statistic_increment(&SSV::ha_read_rnd_count);
6711  // The primary key for the record is stored in pos
6712  // Perform a pk_read using primary key "index"
6713  {
6714  part_id_range part_spec;
6715  uint key_length= ref_length;
6716  if (m_user_defined_partitioning)
6717  {
6718  if (table_share->primary_key == MAX_KEY)
6719  {
6720  /*
6721  The partition id has been fetched from ndb
6722  and has been stored directly after the hidden key
6723  */
6724  DBUG_DUMP("key+part", pos, key_length);
6725  key_length= ref_length - sizeof(m_part_id);
6726  part_spec.start_part= part_spec.end_part= *(uint32 *)(pos + key_length);
6727  }
6728  else
6729  {
6730  key_range key_spec;
6731  KEY *key_info= table->key_info + table_share->primary_key;
6732  key_spec.key= pos;
6733  key_spec.length= key_length;
6734  key_spec.flag= HA_READ_KEY_EXACT;
6735  get_full_part_id_from_key(table, buf, key_info,
6736  &key_spec, &part_spec);
6737  DBUG_ASSERT(part_spec.start_part == part_spec.end_part);
6738  }
6739  DBUG_PRINT("info", ("partition id %u", part_spec.start_part));
6740  }
6741  DBUG_DUMP("key", pos, key_length);
6742  int res= pk_read(pos, key_length, buf,
6743  (m_user_defined_partitioning) ?
6744  &(part_spec.start_part)
6745  : NULL);
6746  if (res == HA_ERR_KEY_NOT_FOUND)
6747  {
6760  res= HA_ERR_RECORD_DELETED;
6761  }
6762  table->status= res ? STATUS_NOT_FOUND: 0;
6763  DBUG_RETURN(res);
6764  }
6765 }
6766 
6767 
6774 void ha_ndbcluster::position(const uchar *record)
6775 {
6776  KEY *key_info;
6777  KEY_PART_INFO *key_part;
6778  KEY_PART_INFO *end;
6779  uchar *buff;
6780  uint key_length;
6781 
6782  DBUG_ENTER("position");
6783 
6784  if (table_share->primary_key != MAX_KEY)
6785  {
6786  key_length= ref_length;
6787  key_info= table->key_info + table_share->primary_key;
6788  key_part= key_info->key_part;
6789  end= key_part + key_info->user_defined_key_parts;
6790  buff= ref;
6791 
6792  for (; key_part != end; key_part++)
6793  {
6794  if (key_part->null_bit) {
6795  /* Store 0 if the key part is a NULL part */
6796  if (record[key_part->null_offset]
6797  & key_part->null_bit) {
6798  *buff++= 1;
6799  continue;
6800  }
6801  *buff++= 0;
6802  }
6803 
6804  size_t len = key_part->length;
6805  const uchar * ptr = record + key_part->offset;
6806  Field *field = key_part->field;
6807  if (field->type() == MYSQL_TYPE_VARCHAR)
6808  {
6809  if (((Field_varstring*)field)->length_bytes == 1)
6810  {
6814  buff[0] = ptr[0];
6815  buff[1] = 0;
6816  memcpy(buff+2, ptr + 1, len);
6817  }
6818  else
6819  {
6820  memcpy(buff, ptr, len + 2);
6821  }
6822  len += 2;
6823  }
6824  else
6825  {
6826  memcpy(buff, ptr, len);
6827  }
6828  buff += len;
6829  }
6830  }
6831  else
6832  {
6833  // No primary key, get hidden key
6834  DBUG_PRINT("info", ("Getting hidden key"));
6835  // If table has user defined partition save the partition id as well
6836  if (m_user_defined_partitioning)
6837  {
6838  DBUG_PRINT("info", ("Saving partition id %u", m_part_id));
6839  key_length= ref_length - sizeof(m_part_id);
6840  memcpy(ref+key_length, (void *)&m_part_id, sizeof(m_part_id));
6841  }
6842  else
6843  key_length= ref_length;
6844 #ifndef DBUG_OFF
6845  int hidden_no= table->s->fields;
6846  const NDBTAB *tab= m_table;
6847  const NDBCOL *hidden_col= tab->getColumn(hidden_no);
6848  DBUG_ASSERT(hidden_col->getPrimaryKey() &&
6849  hidden_col->getAutoIncrement() &&
6850  key_length == NDB_HIDDEN_PRIMARY_KEY_LENGTH);
6851 #endif
6852  memcpy(ref, &m_ref, key_length);
6853  }
6854 #ifndef DBUG_OFF
6855  if (table_share->primary_key == MAX_KEY && m_user_defined_partitioning)
6856  DBUG_DUMP("key+part", ref, key_length+sizeof(m_part_id));
6857 #endif
6858  DBUG_DUMP("ref", ref, key_length);
6859  DBUG_VOID_RETURN;
6860 }
6861 
6862 int
6863 ha_ndbcluster::cmp_ref(const uchar * ref1, const uchar * ref2)
6864 {
6865  DBUG_ENTER("cmp_ref");
6866 
6867  if (table_share->primary_key != MAX_KEY)
6868  {
6869  KEY *key_info= table->key_info + table_share->primary_key;
6870  KEY_PART_INFO *key_part= key_info->key_part;
6871  KEY_PART_INFO *end= key_part + key_info->user_defined_key_parts;
6872 
6873  for (; key_part != end; key_part++)
6874  {
6875  // NOTE: No need to check for null since PK is not-null
6876 
6877  Field *field= key_part->field;
6878  int result= field->key_cmp(ref1, ref2);
6879  if (result)
6880  {
6881  DBUG_RETURN(result);
6882  }
6883 
6884  if (field->type() == MYSQL_TYPE_VARCHAR)
6885  {
6886  ref1+= 2;
6887  ref2+= 2;
6888  }
6889 
6890  ref1+= key_part->length;
6891  ref2+= key_part->length;
6892  }
6893  DBUG_RETURN(0);
6894  }
6895  else
6896  {
6897  DBUG_RETURN(memcmp(ref1, ref2, ref_length));
6898  }
6899 }
6900 
6901 int ha_ndbcluster::info(uint flag)
6902 {
6903  THD *thd= table->in_use;
6904  int result= 0;
6905  DBUG_ENTER("info");
6906  DBUG_PRINT("enter", ("flag: %d", flag));
6907 
6908  if (flag & HA_STATUS_POS)
6909  DBUG_PRINT("info", ("HA_STATUS_POS"));
6910  if (flag & HA_STATUS_TIME)
6911  DBUG_PRINT("info", ("HA_STATUS_TIME"));
6912  while (flag & HA_STATUS_VARIABLE)
6913  {
6914  if (!thd)
6915  thd= current_thd;
6916  DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
6917 
6918  if (!m_table_info)
6919  {
6920  if ((my_errno= check_ndb_connection(thd)))
6921  DBUG_RETURN(my_errno);
6922  }
6923 
6924  /*
6925  May need to update local copy of statistics in
6926  'm_table_info', either directly from datanodes,
6927  or from shared (mutex protected) cached copy, if:
6928  1) 'use_exact_count' has been set (by config or user).
6929  2) HA_STATUS_NO_LOCK -> read from shared cached copy.
6930  3) Local copy is invalid.
6931  */
6932  bool exact_count= THDVAR(thd, use_exact_count);
6933  if (exact_count || // 1)
6934  !(flag & HA_STATUS_NO_LOCK) || // 2)
6935  m_table_info == NULL || // 3)
6936  m_table_info->records == ~(ha_rows)0) // 3)
6937  {
6938  result= update_stats(thd, (exact_count || !(flag & HA_STATUS_NO_LOCK)));
6939  if (result)
6940  DBUG_RETURN(result);
6941  }
6942  /* Read from local statistics, fast and fuzzy, wo/ locks */
6943  else
6944  {
6945  DBUG_ASSERT(m_table_info->records != ~(ha_rows)0);
6946  stats.records= m_table_info->records +
6947  m_table_info->no_uncommitted_rows_count;
6948  }
6949 
6950  if (thd->lex->sql_command != SQLCOM_SHOW_TABLE_STATUS &&
6951  thd->lex->sql_command != SQLCOM_SHOW_KEYS)
6952  {
6953  /*
6954  just use whatever stats we have. However,
6955  optimizer interprets the values 0 and 1 as EXACT:
6956  -> < 2 should not be returned.
6957  */
6958  if (stats.records < 2)
6959  stats.records= 2;
6960  }
6961  break;
6962  }
6963  /* RPK moved to variable part */
6964  if (flag & HA_STATUS_VARIABLE)
6965  {
6966  /* No meaningful way to return error */
6967  DBUG_PRINT("info", ("rec_per_key"));
6968  set_rec_per_key();
6969  }
6970  if (flag & HA_STATUS_ERRKEY)
6971  {
6972  DBUG_PRINT("info", ("HA_STATUS_ERRKEY"));
6973  errkey= m_dupkey;
6974  }
6975  if (flag & HA_STATUS_AUTO)
6976  {
6977  DBUG_PRINT("info", ("HA_STATUS_AUTO"));
6978  if (m_table && table->found_next_number_field)
6979  {
6980  if (!thd)
6981  thd= current_thd;
6982  if ((my_errno= check_ndb_connection(thd)))
6983  DBUG_RETURN(my_errno);
6984  Ndb *ndb= get_ndb(thd);
6985  Ndb_tuple_id_range_guard g(m_share);
6986 
6987  Uint64 auto_increment_value64;
6988  if (ndb->readAutoIncrementValue(m_table, g.range,
6989  auto_increment_value64) == -1)
6990  {
6991  const NdbError err= ndb->getNdbError();
6992  sql_print_error("Error %lu in readAutoIncrementValue(): %s",
6993  (ulong) err.code, err.message);
6994  stats.auto_increment_value= ~(ulonglong)0;
6995  }
6996  else
6997  stats.auto_increment_value= (ulonglong)auto_increment_value64;
6998  }
6999  }
7000 
7001  if(result == -1)
7002  result= HA_ERR_NO_CONNECTION;
7003 
7004  DBUG_RETURN(result);
7005 }
7006 
7007 
7008 void ha_ndbcluster::get_dynamic_partition_info(PARTITION_STATS *stat_info,
7009  uint part_id)
7010 {
7011  DBUG_PRINT("info", ("ha_ndbcluster::get_dynamic_partition_info"));
7012 
7013  memset(stat_info, 0, sizeof(PARTITION_STATS));
7014  int error = 0;
7015  THD *thd = table->in_use;
7016 
7017  if (!thd)
7018  thd = current_thd;
7019  if (!m_table_info)
7020  {
7021  if ((error = check_ndb_connection(thd)))
7022  goto err;
7023  }
7024  error = update_stats(thd, 1, false, part_id);
7025 
7026  if (error == 0)
7027  {
7028  stat_info->records = stats.records;
7029  stat_info->mean_rec_length = stats.mean_rec_length;
7030  stat_info->data_file_length = stats.data_file_length;
7031  stat_info->delete_length = stats.delete_length;
7032  stat_info->max_data_file_length = stats.max_data_file_length;
7033  return;
7034  }
7035 
7036 err:
7037 
7038  DBUG_PRINT("warning",
7039  ("ha_ndbcluster::get_dynamic_partition_info failed with error code %u",
7040  error));
7041 }
7042 
7043 
7044 int ha_ndbcluster::extra(enum ha_extra_function operation)
7045 {
7046  DBUG_ENTER("extra");
7047  switch (operation) {
7048  case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
7049  DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
7050  DBUG_PRINT("info", ("Ignoring duplicate key"));
7051  m_ignore_dup_key= TRUE;
7052  break;
7053  case HA_EXTRA_NO_IGNORE_DUP_KEY:
7054  DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY"));
7055  m_ignore_dup_key= FALSE;
7056  break;
7057  case HA_EXTRA_IGNORE_NO_KEY:
7058  DBUG_PRINT("info", ("HA_EXTRA_IGNORE_NO_KEY"));
7059  DBUG_PRINT("info", ("Turning on AO_IgnoreError at Commit/NoCommit"));
7060  m_ignore_no_key= TRUE;
7061  break;
7062  case HA_EXTRA_NO_IGNORE_NO_KEY:
7063  DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_NO_KEY"));
7064  DBUG_PRINT("info", ("Turning on AO_IgnoreError at Commit/NoCommit"));
7065  m_ignore_no_key= FALSE;
7066  break;
7067  case HA_EXTRA_WRITE_CAN_REPLACE:
7068  DBUG_PRINT("info", ("HA_EXTRA_WRITE_CAN_REPLACE"));
7069  if (!m_has_unique_index ||
7070  current_thd->slave_thread || /* always set if slave, quick fix for bug 27378 */
7071  isManualBinlogExec(current_thd)) /* or if manual binlog application, for bug 46662 */
7072  {
7073  DBUG_PRINT("info", ("Turning ON use of write instead of insert"));
7074  m_use_write= TRUE;
7075  }
7076  break;
7077  case HA_EXTRA_WRITE_CANNOT_REPLACE:
7078  DBUG_PRINT("info", ("HA_EXTRA_WRITE_CANNOT_REPLACE"));
7079  DBUG_PRINT("info", ("Turning OFF use of write instead of insert"));
7080  m_use_write= FALSE;
7081  break;
7082  case HA_EXTRA_DELETE_CANNOT_BATCH:
7083  DBUG_PRINT("info", ("HA_EXTRA_DELETE_CANNOT_BATCH"));
7084  m_delete_cannot_batch= TRUE;
7085  break;
7086  case HA_EXTRA_UPDATE_CANNOT_BATCH:
7087  DBUG_PRINT("info", ("HA_EXTRA_UPDATE_CANNOT_BATCH"));
7088  m_update_cannot_batch= TRUE;
7089  break;
7090  // We don't implement 'KEYREAD'. However, KEYREAD also implies DISABLE_JOINPUSH.
7091  case HA_EXTRA_KEYREAD:
7092  DBUG_PRINT("info", ("HA_EXTRA_KEYREAD"));
7093  m_disable_pushed_join= TRUE;
7094  break;
7095  case HA_EXTRA_NO_KEYREAD:
7096  DBUG_PRINT("info", ("HA_EXTRA_NO_KEYREAD"));
7097  m_disable_pushed_join= FALSE;
7098  break;
7099  default:
7100  break;
7101  }
7102 
7103  DBUG_RETURN(0);
7104 }
7105 
7106 
7108 {
7109  THD *thd= table->in_use;
7110  DBUG_ENTER("start_read_removal");
7111 
7112  if (uses_blob_value(table->write_set))
7113  {
7114  DBUG_PRINT("exit", ("No! Blob field in write_set"));
7115  DBUG_RETURN(false);
7116  }
7117 
7118  if (thd->lex->sql_command == SQLCOM_DELETE &&
7119  table_share->blob_fields)
7120  {
7121  DBUG_PRINT("exit", ("No! DELETE from table with blob(s)"));
7122  DBUG_RETURN(false);
7123  }
7124 
7125  if (table_share->primary_key == MAX_KEY)
7126  {
7127  DBUG_PRINT("exit", ("No! Table with hidden key"));
7128  DBUG_RETURN(false);
7129  }
7130 
7131  if (bitmap_is_overlapping(table->write_set, m_pk_bitmap_p))
7132  {
7133  DBUG_PRINT("exit", ("No! Updating primary key"));
7134  DBUG_RETURN(false);
7135  }
7136 
7137  if (m_has_unique_index)
7138  {
7139  for (uint i= 0; i < table_share->keys; i++)
7140  {
7141  const KEY* key= table->key_info + i;
7142  if ((key->flags & HA_NOSAME) &&
7143  bitmap_is_overlapping(table->write_set,
7144  m_key_fields[i]))
7145  {
7146  DBUG_PRINT("exit", ("No! Unique key %d is updated", i));
7147  DBUG_RETURN(false);
7148  }
7149  }
7150  }
7151  m_read_before_write_removal_possible= TRUE;
7152  DBUG_PRINT("exit", ("Yes, rbwr is possible!"));
7153  DBUG_RETURN(true);
7154 }
7155 
7156 
7157 ha_rows ha_ndbcluster::end_read_removal(void)
7158 {
7159  DBUG_ENTER("end_read_removal");
7160  DBUG_ASSERT(m_read_before_write_removal_possible);
7161  DBUG_PRINT("info", ("updated: %llu, deleted: %llu",
7162  m_rows_updated, m_rows_deleted));
7163  DBUG_RETURN(m_rows_updated + m_rows_deleted);
7164 }
7165 
7166 
7168 {
7169  DBUG_ENTER("ha_ndbcluster::reset");
7170  if (m_cond)
7171  {
7172  m_cond->cond_clear();
7173  }
7174 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
7175  DBUG_ASSERT(m_active_query == NULL);
7176  if (m_pushed_join_operation==PUSHED_ROOT) // Root of pushed query
7177  {
7178  delete m_pushed_join_member; // Also delete QueryDef
7179  }
7180  m_pushed_join_member= NULL;
7181  m_pushed_join_operation= -1;
7182  m_disable_pushed_join= FALSE;
7183 #endif
7184 
7185 #if 0
7186  // Magnus, disble this "hack" until it's possible to test if
7187  // it's still needed
7188  /*
7189  Regular partition pruning will set the bitmap appropriately.
7190  Some queries like ALTER TABLE doesn't use partition pruning and
7191  thus the 'used_partitions' bitmap needs to be initialized
7192  */
7193  if (m_part_info)
7194  bitmap_set_all(&m_part_info->used_partitions);
7195 #endif
7196 
7197  /* reset flags set by extra calls */
7198  m_read_before_write_removal_possible= FALSE;
7199  m_read_before_write_removal_used= FALSE;
7200  m_rows_updated= m_rows_deleted= 0;
7201  m_ignore_dup_key= FALSE;
7202  m_use_write= FALSE;
7203  m_ignore_no_key= FALSE;
7204  m_rows_inserted= (ha_rows) 0;
7205  m_rows_to_insert= (ha_rows) 1;
7206  m_delete_cannot_batch= FALSE;
7207  m_update_cannot_batch= FALSE;
7208 
7209  assert(m_is_bulk_delete == false);
7210  m_is_bulk_delete = false;
7211  DBUG_RETURN(0);
7212 }
7213 
7214 
7224 int
7225 ha_ndbcluster::flush_bulk_insert(bool allow_batch)
7226 {
7227  NdbTransaction *trans= m_thd_ndb->trans;
7228  DBUG_ENTER("ha_ndbcluster::flush_bulk_insert");
7229  DBUG_PRINT("info", ("Sending inserts to NDB, rows_inserted: %d",
7230  (int)m_rows_inserted));
7231  DBUG_ASSERT(trans);
7232 
7233 
7234  if (! (m_thd_ndb->trans_options & TNTO_TRANSACTIONS_OFF))
7235  {
7236  if (!allow_batch &&
7237  execute_no_commit(m_thd_ndb, trans, m_ignore_no_key) != 0)
7238  {
7239  no_uncommitted_rows_execute_failure();
7240  DBUG_RETURN(ndb_err(trans));
7241  }
7242  }
7243  else
7244  {
7245  /*
7246  signal that transaction has been broken up and hence cannot
7247  be rolled back
7248  */
7249  THD *thd= table->in_use;
7250  thd->transaction.all.mark_modified_non_trans_table();
7251  thd->transaction.stmt.mark_modified_non_trans_table();
7252  if (execute_commit(thd, m_thd_ndb, trans, m_thd_ndb->m_force_send,
7253  m_ignore_no_key) != 0)
7254  {
7255  no_uncommitted_rows_execute_failure();
7256  DBUG_RETURN(ndb_err(trans));
7257  }
7258  if (trans->restart() != 0)
7259  {
7260  DBUG_ASSERT(0);
7261  DBUG_RETURN(-1);
7262  }
7263  }
7264  DBUG_RETURN(0);
7265 }
7266 
7267 void ha_ndbcluster::start_bulk_insert(ha_rows rows)
7268 {
7269  DBUG_ENTER("start_bulk_insert");
7270  DBUG_PRINT("enter", ("rows: %d", (int)rows));
7271 
7272  m_rows_inserted= (ha_rows) 0;
7273  if (!m_use_write && m_ignore_dup_key)
7274  {
7275  /*
7276  compare if expression with that in write_row
7277  we have a situation where peek_indexed_rows() will be called
7278  so we cannot batch
7279  */
7280  DBUG_PRINT("info", ("Batching turned off as duplicate key is "
7281  "ignored by using peek_row"));
7282  m_rows_to_insert= 1;
7283  DBUG_VOID_RETURN;
7284  }
7285  if (rows == (ha_rows) 0)
7286  {
7287  /* We don't know how many will be inserted, guess */
7288  m_rows_to_insert=
7289  (m_autoincrement_prefetch > DEFAULT_AUTO_PREFETCH)
7290  ? m_autoincrement_prefetch
7291  : DEFAULT_AUTO_PREFETCH;
7292  m_autoincrement_prefetch= m_rows_to_insert;
7293  }
7294  else
7295  {
7296  m_rows_to_insert= rows;
7297  if (m_autoincrement_prefetch < m_rows_to_insert)
7298  m_autoincrement_prefetch= m_rows_to_insert;
7299  }
7300 
7301  DBUG_VOID_RETURN;
7302 }
7303 
7307 int ha_ndbcluster::end_bulk_insert()
7308 {
7309  int error= 0;
7310 
7311  DBUG_ENTER("end_bulk_insert");
7312  // Check if last inserts need to be flushed
7313 
7314  THD *thd= table->in_use;
7315  Thd_ndb *thd_ndb= m_thd_ndb;
7316 
7317  if (!thd_allow_batch(thd) && thd_ndb->m_unsent_bytes)
7318  {
7319  bool allow_batch= (thd_ndb->m_handler != 0);
7320  error= flush_bulk_insert(allow_batch);
7321  if (error != 0)
7322  my_errno= error;
7323  }
7324 
7325  m_rows_inserted= (ha_rows) 0;
7326  m_rows_to_insert= (ha_rows) 1;
7327  DBUG_RETURN(error);
7328 }
7329 
7330 
7331 int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size)
7332 {
7333  DBUG_ENTER("extra_opt");
7334  DBUG_PRINT("enter", ("cache_size: %lu", cache_size));
7335  DBUG_RETURN(extra(operation));
7336 }
7337 
7338 static const char *ha_ndbcluster_exts[] = {
7339  ha_ndb_ext,
7340  NullS
7341 };
7342 
7343 const char** ha_ndbcluster::bas_ext() const
7344 {
7345  return ha_ndbcluster_exts;
7346 }
7347 
7355 double ha_ndbcluster::scan_time()
7356 {
7357  DBUG_ENTER("ha_ndbcluster::scan_time()");
7358  double res= rows2double(stats.records*1000);
7359  DBUG_PRINT("exit", ("table: %s value: %f",
7360  m_tabname, res));
7361  DBUG_RETURN(res);
7362 }
7363 
7364 /*
7365  Convert MySQL table locks into locks supported by Ndb Cluster.
7366  Note that MySQL Cluster does currently not support distributed
7367  table locks, so to be safe one should set cluster in Single
7368  User Mode, before relying on table locks when updating tables
7369  from several MySQL servers
7370 */
7371 
7373  THR_LOCK_DATA **to,
7374  enum thr_lock_type lock_type)
7375 {
7376  DBUG_ENTER("store_lock");
7377  if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK)
7378  {
7379 
7380  /* If we are not doing a LOCK TABLE, then allow multiple
7381  writers */
7382 
7383  /* Since NDB does not currently have table locks
7384  this is treated as a ordinary lock */
7385 
7386  const bool in_lock_tables = thd_in_lock_tables(thd);
7387  const uint sql_command = thd_sql_command(thd);
7388  if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
7389  lock_type <= TL_WRITE) &&
7390  !(in_lock_tables && sql_command == SQLCOM_LOCK_TABLES))
7391  lock_type= TL_WRITE_ALLOW_WRITE;
7392 
7393  /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
7394  MySQL would use the lock TL_READ_NO_INSERT on t2, and that
7395  would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
7396  to t2. Convert the lock to a normal read lock to allow
7397  concurrent inserts to t2. */
7398 
7399  if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables)
7400  lock_type= TL_READ;
7401 
7409  if (sql_command == SQLCOM_ALTER_TABLE)
7410  lock_type = TL_WRITE;
7411 
7412  m_lock.type=lock_type;
7413  }
7414  *to++= &m_lock;
7415 
7416  DBUG_PRINT("exit", ("lock_type: %d", lock_type));
7417 
7418  DBUG_RETURN(to);
7419 }
7420 
7421 /*
7422  As MySQL will execute an external lock for every new table it uses
7423  we can use this to start the transactions.
7424  If we are in auto_commit mode we just need to start a transaction
7425  for the statement, this will be stored in thd_ndb.stmt.
7426  If not, we have to start a master transaction if there doesn't exist
7427  one from before, this will be stored in thd_ndb.all
7428 
7429  When a table lock is held one transaction will be started which holds
7430  the table lock and for each statement a hupp transaction will be started
7431  If we are locking the table then:
7432  - save the NdbDictionary::Table for easy access
7433  - save reference to table statistics
7434  - refresh list of the indexes for the table if needed (if altered)
7435  */
7436 
7437 #ifdef HAVE_NDB_BINLOG
7438 static int ndbcluster_update_apply_status(THD *thd, int do_update)
7439 {
7440  Thd_ndb *thd_ndb= get_thd_ndb(thd);
7441  Ndb *ndb= thd_ndb->ndb;
7442  NDBDICT *dict= ndb->getDictionary();
7443  const NDBTAB *ndbtab;
7444  NdbTransaction *trans= thd_ndb->trans;
7445  ndb->setDatabaseName(NDB_REP_DB);
7446  Ndb_table_guard ndbtab_g(dict, NDB_APPLY_TABLE);
7447  if (!(ndbtab= ndbtab_g.get_table()))
7448  {
7449  return -1;
7450  }
7451  NdbOperation *op= 0;
7452  int r= 0;
7453  r|= (op= trans->getNdbOperation(ndbtab)) == 0;
7454  DBUG_ASSERT(r == 0);
7455  if (do_update)
7456  r|= op->updateTuple();
7457  else
7458  r|= op->writeTuple();
7459  DBUG_ASSERT(r == 0);
7460  // server_id
7461  r|= op->equal(0u, (Uint32)thd->server_id);
7462  DBUG_ASSERT(r == 0);
7463  if (!do_update)
7464  {
7465  // epoch
7466  r|= op->setValue(1u, (Uint64)0);
7467  DBUG_ASSERT(r == 0);
7468  }
7469  const char* group_master_log_name =
7470  ndb_mi_get_group_master_log_name();
7471  const Uint64 group_master_log_pos =
7472  ndb_mi_get_group_master_log_pos();
7473  const Uint64 future_event_relay_log_pos =
7474  ndb_mi_get_future_event_relay_log_pos();
7475  const Uint64 group_relay_log_pos =
7476  ndb_mi_get_group_relay_log_pos();
7477 
7478  // log_name
7479  char tmp_buf[FN_REFLEN];
7480  ndb_pack_varchar(ndbtab->getColumn(2u), tmp_buf,
7481  group_master_log_name, strlen(group_master_log_name));
7482  r|= op->setValue(2u, tmp_buf);
7483  DBUG_ASSERT(r == 0);
7484  // start_pos
7485  r|= op->setValue(3u, group_master_log_pos);
7486  DBUG_ASSERT(r == 0);
7487  // end_pos
7488  r|= op->setValue(4u, group_master_log_pos +
7489  (future_event_relay_log_pos - group_relay_log_pos));
7490  DBUG_ASSERT(r == 0);
7491  return 0;
7492 }
7493 #endif /* HAVE_NDB_BINLOG */
7494 
7495 static void transaction_checks(THD *thd, Thd_ndb *thd_ndb)
7496 {
7497  if (thd->lex->sql_command == SQLCOM_LOAD)
7498  thd_ndb->trans_options|= TNTO_TRANSACTIONS_OFF;
7499  else if (!thd->transaction.flags.enabled)
7500  thd_ndb->trans_options|= TNTO_TRANSACTIONS_OFF;
7501  else if (!THDVAR(thd, use_transactions))
7502  thd_ndb->trans_options|= TNTO_TRANSACTIONS_OFF;
7503  thd_ndb->m_force_send= THDVAR(thd, force_send);
7504  if (!thd->slave_thread)
7505  thd_ndb->m_batch_size= THDVAR(thd, batch_size);
7506  else
7507  {
7508  thd_ndb->m_batch_size= THDVAR(NULL, batch_size); /* using global value */
7509  /* Do not use hinted TC selection in slave thread */
7510  THDVAR(thd, optimized_node_selection)=
7511  THDVAR(NULL, optimized_node_selection) & 1; /* using global value */
7512  }
7513 }
7514 
7515 int ha_ndbcluster::start_statement(THD *thd,
7516  Thd_ndb *thd_ndb,
7517  uint table_count)
7518 {
7519  NdbTransaction *trans= thd_ndb->trans;
7520  int error;
7521  DBUG_ENTER("ha_ndbcluster::start_statement");
7522 
7523  m_thd_ndb= thd_ndb;
7524  transaction_checks(thd, m_thd_ndb);
7525 
7526  if (table_count == 0)
7527  {
7528  trans_register_ha(thd, FALSE, ndbcluster_hton);
7529  if (thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
7530  {
7531  if (!trans)
7532  trans_register_ha(thd, TRUE, ndbcluster_hton);
7533  thd_ndb->m_handler= NULL;
7534  }
7535  else
7536  {
7537  /*
7538  this is an autocommit, we may keep a reference to the
7539  handler to be used in the commit phase for optimization
7540  reasons, defering execute
7541  */
7542  thd_ndb->m_handler= this;
7543  }
7544  }
7545  else
7546  {
7547  /*
7548  there is more than one handler involved, execute deferal
7549  not possible
7550  */
7551  ha_ndbcluster* handler = thd_ndb->m_handler;
7552  thd_ndb->m_handler= NULL;
7553  if (handler != NULL)
7554  {
7561  add_handler_to_open_tables(thd, thd_ndb, handler);
7562  }
7563  }
7564  if (!trans && table_count == 0)
7565  {
7566  DBUG_ASSERT(thd_ndb->changed_tables.is_empty() == TRUE);
7567  thd_ndb->trans_options= 0;
7568 
7569  DBUG_PRINT("trans",("Possibly starting transaction"));
7570  const uint opti_node_select = THDVAR(thd, optimized_node_selection);
7571  DBUG_PRINT("enter", ("optimized_node_selection: %u", opti_node_select));
7572  if (!(opti_node_select & 2) ||
7573  thd->lex->sql_command == SQLCOM_LOAD)
7574  if (unlikely(!start_transaction(error)))
7575  DBUG_RETURN(error);
7576 
7577  thd_ndb->init_open_tables();
7578  thd_ndb->m_slow_path= FALSE;
7579  if (!(thd_options(thd) & OPTION_BIN_LOG) ||
7580  thd->variables.binlog_format == BINLOG_FORMAT_STMT)
7581  {
7582  thd_ndb->trans_options|= TNTO_NO_LOGGING;
7583  thd_ndb->m_slow_path= TRUE;
7584  }
7585  else if (thd->slave_thread)
7586  thd_ndb->m_slow_path= TRUE;
7587  }
7588  /*
7589  If this is the start of a LOCK TABLE, a table look
7590  should be taken on the table in NDB
7591 
7592  Check if it should be read or write lock
7593  */
7594  if (thd_options(thd) & (OPTION_TABLE_LOCK))
7595  {
7596  /* This is currently dead code in wait for implementation in NDB */
7597  /* lockThisTable(); */
7598  DBUG_PRINT("info", ("Locking the table..." ));
7599 #ifdef NOT_YET
7600  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
7601  ER_GET_ERRMSG, ER(ER_GET_ERRMSG), 0,
7602  "Table only locked locally in this mysqld", "NDB");
7603 #endif
7604  }
7605  DBUG_RETURN(0);
7606 }
7607 
7608 int
7609 ha_ndbcluster::add_handler_to_open_tables(THD *thd,
7610  Thd_ndb *thd_ndb,
7611  ha_ndbcluster* handler)
7612 {
7613  DBUG_ENTER("ha_ndbcluster::add_handler_to_open_tables");
7614  DBUG_PRINT("info", ("Adding %s", handler->m_share->key));
7615 
7619  DBUG_ASSERT(thd_ndb->m_handler == NULL);
7620  const void *key= handler->m_share;
7621  HASH_SEARCH_STATE state;
7622  THD_NDB_SHARE *thd_ndb_share=
7623  (THD_NDB_SHARE*)my_hash_first(&thd_ndb->open_tables,
7624  (const uchar *)&key, sizeof(key),
7625  &state);
7626  while (thd_ndb_share && thd_ndb_share->key != key)
7627  {
7628  thd_ndb_share=
7629  (THD_NDB_SHARE*)my_hash_next(&thd_ndb->open_tables,
7630  (const uchar *)&key, sizeof(key),
7631  &state);
7632  }
7633  if (thd_ndb_share == 0)
7634  {
7635  thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root,
7636  sizeof(THD_NDB_SHARE));
7637  if (!thd_ndb_share)
7638  {
7639  mem_alloc_error(sizeof(THD_NDB_SHARE));
7640  DBUG_RETURN(1);
7641  }
7642  thd_ndb_share->key= key;
7643  thd_ndb_share->stat.last_count= thd_ndb->count;
7644  thd_ndb_share->stat.no_uncommitted_rows_count= 0;
7645  thd_ndb_share->stat.records= ~(ha_rows)0;
7646  my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share);
7647  }
7648  else if (thd_ndb_share->stat.last_count != thd_ndb->count)
7649  {
7650  thd_ndb_share->stat.last_count= thd_ndb->count;
7651  thd_ndb_share->stat.no_uncommitted_rows_count= 0;
7652  thd_ndb_share->stat.records= ~(ha_rows)0;
7653  }
7654 
7655  handler->m_table_info= &thd_ndb_share->stat;
7656  DBUG_RETURN(0);
7657 }
7658 
7659 int ha_ndbcluster::init_handler_for_statement(THD *thd)
7660 {
7661  /*
7662  This is the place to make sure this handler instance
7663  has a started transaction.
7664 
7665  The transaction is started by the first handler on which
7666  MySQL Server calls external lock
7667 
7668  Other handlers in the same stmt or transaction should use
7669  the same NDB transaction. This is done by setting up the m_thd_ndb
7670  pointer to point to the NDB transaction object.
7671  */
7672 
7673  DBUG_ENTER("ha_ndbcluster::init_handler_for_statement");
7674  Thd_ndb *thd_ndb= m_thd_ndb;
7675  DBUG_ASSERT(thd_ndb);
7676 
7677  // store thread specific data first to set the right context
7678  m_autoincrement_prefetch= THDVAR(thd, autoincrement_prefetch_sz);
7679  // Start of transaction
7680  m_rows_changed= 0;
7681  m_blobs_pending= FALSE;
7682  release_blobs_buffer();
7683  m_slow_path= m_thd_ndb->m_slow_path;
7684 #ifdef HAVE_NDB_BINLOG
7685  if (unlikely(m_slow_path))
7686  {
7687  if (m_share == ndb_apply_status_share && thd->slave_thread)
7688  m_thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS;
7689  }
7690 #endif
7691 
7692  int ret = 0;
7693  if (thd_ndb->m_handler == 0)
7694  {
7695  DBUG_ASSERT(m_share);
7696  ret = add_handler_to_open_tables(thd, thd_ndb, this);
7697  }
7698  else
7699  {
7700  struct Ndb_local_table_statistics &stat= m_table_info_instance;
7701  stat.last_count= thd_ndb->count;
7702  stat.no_uncommitted_rows_count= 0;
7703  stat.records= ~(ha_rows)0;
7704  m_table_info= &stat;
7705  }
7706  DBUG_RETURN(ret);
7707 }
7708 
7709 int ha_ndbcluster::external_lock(THD *thd, int lock_type)
7710 {
7711  DBUG_ENTER("external_lock");
7712  if (lock_type != F_UNLCK)
7713  {
7714  int error;
7715  /*
7716  Check that this handler instance has a connection
7717  set up to the Ndb object of thd
7718  */
7719  if (check_ndb_connection(thd))
7720  DBUG_RETURN(1);
7721  Thd_ndb *thd_ndb= get_thd_ndb(thd);
7722 
7723  DBUG_PRINT("enter", ("lock_type != F_UNLCK "
7724  "this: 0x%lx thd: 0x%lx thd_ndb: %lx "
7725  "thd_ndb->lock_count: %d",
7726  (long) this, (long) thd, (long) thd_ndb,
7727  thd_ndb->lock_count));
7728 
7729  if ((error= start_statement(thd, thd_ndb,
7730  thd_ndb->lock_count++)))
7731  {
7732  thd_ndb->lock_count--;
7733  DBUG_RETURN(error);
7734  }
7735  if ((error= init_handler_for_statement(thd)))
7736  {
7737  thd_ndb->lock_count--;
7738  DBUG_RETURN(error);
7739  }
7740  DBUG_RETURN(0);
7741  }
7742  else
7743  {
7744  Thd_ndb *thd_ndb= m_thd_ndb;
7745  DBUG_ASSERT(thd_ndb);
7746 
7747  DBUG_PRINT("enter", ("lock_type == F_UNLCK "
7748  "this: 0x%lx thd: 0x%lx thd_ndb: %lx "
7749  "thd_ndb->lock_count: %d",
7750  (long) this, (long) thd, (long) thd_ndb,
7751  thd_ndb->lock_count));
7752 
7753  if (m_rows_changed && global_system_variables.query_cache_type)
7754  {
7755  DBUG_PRINT("info", ("Rows has changed"));
7756 
7757  if (thd_ndb->trans &&
7758  thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
7759  {
7760  DBUG_PRINT("info", ("Add share to list of changed tables, %p",
7761  m_share));
7762  /* NOTE push_back allocates memory using transactions mem_root! */
7763  thd_ndb->changed_tables.push_back(get_share(m_share),
7764  &thd->transaction.mem_root);
7765  }
7766 
7767  if (opt_ndb_cache_check_time)
7768  {
7769  pthread_mutex_lock(&m_share->mutex);
7770  DBUG_PRINT("info", ("Invalidating commit_count"));
7771  m_share->commit_count= 0;
7772  m_share->commit_count_lock++;
7773  pthread_mutex_unlock(&m_share->mutex);
7774  }
7775  }
7776 
7777  if (!--thd_ndb->lock_count)
7778  {
7779  DBUG_PRINT("trans", ("Last external_lock"));
7780 
7781  if ((!(thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) &&
7782  thd_ndb->trans)
7783  {
7784  if (thd_ndb->trans)
7785  {
7786  /*
7787  Unlock is done without a transaction commit / rollback.
7788  This happens if the thread didn't update any rows
7789  We must in this case close the transaction to release resources
7790  */
7791  DBUG_PRINT("trans",("ending non-updating transaction"));
7792  thd_ndb->ndb->closeTransaction(thd_ndb->trans);
7793  thd_ndb->trans= NULL;
7794  thd_ndb->m_handler= NULL;
7795  }
7796  }
7797  }
7798  m_table_info= NULL;
7799 
7800  /*
7801  This is the place to make sure this handler instance
7802  no longer are connected to the active transaction.
7803 
7804  And since the handler is no longer part of the transaction
7805  it can't have open cursors, ops, queries or blobs pending.
7806  */
7807  m_thd_ndb= NULL;
7808 
7809  if (m_active_query)
7810  DBUG_PRINT("warning", ("m_active_query != NULL"));
7811  m_active_query= NULL;
7812 
7813  if (m_active_cursor)
7814  DBUG_PRINT("warning", ("m_active_cursor != NULL"));
7815  m_active_cursor= NULL;
7816 
7817  if (m_multi_cursor)
7818  DBUG_PRINT("warning", ("m_multi_cursor != NULL"));
7819  m_multi_cursor= NULL;
7820 
7821  if (m_blobs_pending)
7822  DBUG_PRINT("warning", ("blobs_pending != 0"));
7823  m_blobs_pending= 0;
7824 
7825  DBUG_RETURN(0);
7826  }
7827 }
7828 
7836 void ha_ndbcluster::unlock_row()
7837 {
7838  DBUG_ENTER("unlock_row");
7839 
7840  DBUG_PRINT("info", ("Unlocking row"));
7841  m_lock_tuple= FALSE;
7842  DBUG_VOID_RETURN;
7843 }
7844 
7869 int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
7870 {
7871  int error=0;
7872  Thd_ndb *thd_ndb;
7873  DBUG_ENTER("start_stmt");
7874  DBUG_ASSERT(thd == table->in_use);
7875 
7876  thd_ndb= get_thd_ndb(thd);
7877  if ((error= start_statement(thd, thd_ndb, thd_ndb->start_stmt_count++)))
7878  goto error;
7879  if ((error= init_handler_for_statement(thd)))
7880  goto error;
7881  DBUG_RETURN(0);
7882 error:
7883  thd_ndb->start_stmt_count--;
7884  DBUG_RETURN(error);
7885 }
7886 
7888 ha_ndbcluster::start_transaction_row(const NdbRecord *ndb_record,
7889  const uchar *record,
7890  int &error)
7891 {
7892  NdbTransaction *trans;
7893  DBUG_ENTER("ha_ndbcluster::start_transaction_row");
7894  DBUG_ASSERT(m_thd_ndb);
7895  DBUG_ASSERT(m_thd_ndb->trans == NULL);
7896 
7897  transaction_checks(table->in_use, m_thd_ndb);
7898 
7899  Ndb *ndb= m_thd_ndb->ndb;
7900 
7901  Uint64 tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1];
7902  char *buf= (char*)&tmp[0];
7903  trans= ndb->startTransaction(ndb_record,
7904  (const char*)record,
7905  buf, sizeof(tmp));
7906 
7907  if (trans)
7908  {
7909  m_thd_ndb->m_transaction_hint_count[trans->getConnectedNodeId()]++;
7910  DBUG_PRINT("info", ("Delayed allocation of TC"));
7911  DBUG_RETURN(m_thd_ndb->trans= trans);
7912  }
7913 
7914  ERR_SET(m_thd_ndb->ndb->getNdbError(), error);
7915  DBUG_RETURN(NULL);
7916 }
7917 
7919 ha_ndbcluster::start_transaction_key(uint inx_no,
7920  const uchar *key_data,
7921  int &error)
7922 {
7923  NdbTransaction *trans;
7924  DBUG_ENTER("ha_ndbcluster::start_transaction_key");
7925  DBUG_ASSERT(m_thd_ndb);
7926  DBUG_ASSERT(m_thd_ndb->trans == NULL);
7927 
7928  transaction_checks(table->in_use, m_thd_ndb);
7929 
7930  Ndb *ndb= m_thd_ndb->ndb;
7931  const NdbRecord *key_rec= m_index[inx_no].ndb_unique_record_key;
7932 
7933  Uint64 tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1];
7934  char *buf= (char*)&tmp[0];
7935  trans= ndb->startTransaction(key_rec,
7936  (const char*)key_data,
7937  buf, sizeof(tmp));
7938 
7939  if (trans)
7940  {
7941  m_thd_ndb->m_transaction_hint_count[trans->getConnectedNodeId()]++;
7942  DBUG_PRINT("info", ("Delayed allocation of TC"));
7943  DBUG_RETURN(m_thd_ndb->trans= trans);
7944  }
7945 
7946  ERR_SET(m_thd_ndb->ndb->getNdbError(), error);
7947  DBUG_RETURN(NULL);
7948 }
7949 
7951 ha_ndbcluster::start_transaction(int &error)
7952 {
7953  NdbTransaction *trans;
7954  DBUG_ENTER("ha_ndbcluster::start_transaction");
7955 
7956  DBUG_ASSERT(m_thd_ndb);
7957  DBUG_ASSERT(m_thd_ndb->trans == NULL);
7958 
7959  transaction_checks(table->in_use, m_thd_ndb);
7960  const uint opti_node_select= THDVAR(table->in_use, optimized_node_selection);
7961  m_thd_ndb->connection->set_optimized_node_selection(opti_node_select & 1);
7962  if ((trans= m_thd_ndb->ndb->startTransaction()))
7963  {
7964  m_thd_ndb->m_transaction_no_hint_count[trans->getConnectedNodeId()]++;
7965  DBUG_PRINT("info", ("Delayed allocation of TC"));
7966  DBUG_RETURN(m_thd_ndb->trans= trans);
7967  }
7968 
7969  ERR_SET(m_thd_ndb->ndb->getNdbError(), error);
7970  DBUG_RETURN(NULL);
7971 }
7972 
7974 ha_ndbcluster::start_transaction_part_id(Uint32 part_id, int &error)
7975 {
7976  NdbTransaction *trans;
7977  DBUG_ENTER("ha_ndbcluster::start_transaction_part_id");
7978 
7979  DBUG_ASSERT(m_thd_ndb);
7980  DBUG_ASSERT(m_thd_ndb->trans == NULL);
7981 
7982  transaction_checks(table->in_use, m_thd_ndb);
7983  if ((trans= m_thd_ndb->ndb->startTransaction(m_table, part_id)))
7984  {
7985  m_thd_ndb->m_transaction_hint_count[trans->getConnectedNodeId()]++;
7986  DBUG_PRINT("info", ("Delayed allocation of TC"));
7987  DBUG_RETURN(m_thd_ndb->trans= trans);
7988  }
7989 
7990  ERR_SET(m_thd_ndb->ndb->getNdbError(), error);
7991  DBUG_RETURN(NULL);
7992 }
7993 
7994 
7999 int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
8000 {
8001  int res= 0;
8002  Thd_ndb *thd_ndb= get_thd_ndb(thd);
8003  Ndb *ndb= thd_ndb->ndb;
8004  NdbTransaction *trans= thd_ndb->trans;
8005 
8006  DBUG_ENTER("ndbcluster_commit");
8007  DBUG_ASSERT(ndb);
8008  DBUG_PRINT("enter", ("Commit %s", (all ? "all" : "stmt")));
8009  thd_ndb->start_stmt_count= 0;
8010  if (trans == NULL)
8011  {
8012  DBUG_PRINT("info", ("trans == NULL"));
8013  DBUG_RETURN(0);
8014  }
8015  if (!all && (thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
8016  {
8017  /*
8018  An odditity in the handler interface is that commit on handlerton
8019  is called to indicate end of statement only in cases where
8020  autocommit isn't used and the all flag isn't set.
8021 
8022  We also leave quickly when a transaction haven't even been started,
8023  in this case we are safe that no clean up is needed. In this case
8024  the MySQL Server could handle the query without contacting the
8025  NDB kernel.
8026  */
8027  thd_ndb->save_point_count++;
8028  DBUG_PRINT("info", ("Commit before start or end-of-statement only"));
8029  DBUG_RETURN(0);
8030  }
8031  thd_ndb->save_point_count= 0;
8032 
8033 #ifdef HAVE_NDB_BINLOG
8034  if (unlikely(thd_ndb->m_slow_path))
8035  {
8036  if (thd->slave_thread)
8037  ndbcluster_update_apply_status
8038  (thd, thd_ndb->trans_options & TNTO_INJECTED_APPLY_STATUS);
8039  }
8040 #endif /* HAVE_NDB_BINLOG */
8041 
8042  if (thd->slave_thread)
8043  {
8044  if (!g_ndb_slave_state.current_conflict_defined_op_count ||
8045  !thd_ndb->m_unsent_bytes ||
8046  !(res= execute_no_commit(thd_ndb, trans, TRUE)))
8047  res= execute_commit(thd, thd_ndb, trans, 1, TRUE);
8048 
8049  update_slave_api_stats(thd_ndb->ndb);
8050  }
8051  else
8052  {
8053  if (thd_ndb->m_handler &&
8054  thd_ndb->m_handler->m_read_before_write_removal_possible)
8055  {
8056  /*
8057  This is an autocommit involving only one table and
8058  rbwr is on, thus the transaction has already been
8059  committed in exec_bulk_update() or end_bulk_delete()
8060  */
8061  DBUG_PRINT("info", ("autocommit+rbwr, transaction already comitted"));
8062  if (trans->commitStatus() != NdbTransaction::Committed)
8063  {
8064  sql_print_error("found uncomitted autocommit+rbwr transaction, "
8065  "commit status: %d", trans->commitStatus());
8066  abort();
8067  }
8068  }
8069  else
8070  res= execute_commit(thd, thd_ndb, trans, THDVAR(thd, force_send), FALSE);
8071  }
8072 
8073  if (res != 0)
8074  {
8075  const NdbError err= trans->getNdbError();
8076  const NdbOperation *error_op= trans->getNdbErrorOperation();
8077  res= ndb_to_mysql_error(&err);
8078  if (res != -1)
8079  ndbcluster_print_error(res, error_op);
8080  }
8081  else
8082  {
8083  /* Update shared statistics for tables inserted into / deleted from*/
8084  if (thd_ndb->m_handler && // Autocommit Txn
8085  thd_ndb->m_handler->m_share &&
8086  thd_ndb->m_handler->m_table_info)
8087  {
8088  modify_shared_stats(thd_ndb->m_handler->m_share, thd_ndb->m_handler->m_table_info);
8089  }
8090 
8091  /* Manual commit: Update all affected NDB_SHAREs found in 'open_tables' */
8092  for (uint i= 0; i<thd_ndb->open_tables.records; i++)
8093  {
8094  THD_NDB_SHARE *thd_share=
8095  (THD_NDB_SHARE*)my_hash_element(&thd_ndb->open_tables, i);
8096  modify_shared_stats((NDB_SHARE*)thd_share->key, &thd_share->stat);
8097  }
8098  }
8099 
8100  ndb->closeTransaction(trans);
8101  thd_ndb->trans= NULL;
8102  thd_ndb->m_handler= NULL;
8103 
8104  /* Clear commit_count for tables changed by transaction */
8105  NDB_SHARE* share;
8106  List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
8107  while ((share= it++))
8108  {
8109  DBUG_PRINT("info", ("Remove share to list of changed tables, %p",
8110  share));
8111  pthread_mutex_lock(&share->mutex);
8112  DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %lu",
8113  share->table_name, (ulong) share->commit_count));
8114  share->commit_count= 0;
8115  share->commit_count_lock++;
8116  pthread_mutex_unlock(&share->mutex);
8117  free_share(&share);
8118  }
8119  thd_ndb->changed_tables.empty();
8120 
8121  DBUG_RETURN(res);
8122 }
8123 
8124 
8129 static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all)
8130 {
8131  int res= 0;
8132  Thd_ndb *thd_ndb= get_thd_ndb(thd);
8133  Ndb *ndb= thd_ndb->ndb;
8134  NdbTransaction *trans= thd_ndb->trans;
8135 
8136  DBUG_ENTER("ndbcluster_rollback");
8137  DBUG_PRINT("enter", ("all: %d thd_ndb->save_point_count: %d",
8138  all, thd_ndb->save_point_count));
8139  DBUG_ASSERT(ndb);
8140  thd_ndb->start_stmt_count= 0;
8141  if (trans == NULL)
8142  {
8143  /* Ignore end-of-statement until real rollback or commit is called */
8144  DBUG_PRINT("info", ("trans == NULL"));
8145  DBUG_RETURN(0);
8146  }
8147  if (!all && (thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
8148  (thd_ndb->save_point_count > 0))
8149  {
8150  /*
8151  Ignore end-of-statement until real rollback or commit is called
8152  as ndb does not support rollback statement
8153  - mark that rollback was unsuccessful, this will cause full rollback
8154  of the transaction
8155  */
8156  DBUG_PRINT("info", ("Rollback before start or end-of-statement only"));
8157  mark_transaction_to_rollback(thd, 1);
8158  my_error(ER_WARN_ENGINE_TRANSACTION_ROLLBACK, MYF(0), "NDB");
8159  DBUG_RETURN(0);
8160  }
8161  thd_ndb->save_point_count= 0;
8162  if (thd->slave_thread)
8163  g_ndb_slave_state.atTransactionAbort();
8164  thd_ndb->m_unsent_bytes= 0;
8165  thd_ndb->m_execute_count++;
8166  DBUG_PRINT("info", ("execute_count: %u", thd_ndb->m_execute_count));
8167  if (trans->execute(NdbTransaction::Rollback) != 0)
8168  {
8169  const NdbError err= trans->getNdbError();
8170  const NdbOperation *error_op= trans->getNdbErrorOperation();
8171  res= ndb_to_mysql_error(&err);
8172  if (res != -1)
8173  ndbcluster_print_error(res, error_op);
8174  }
8175  ndb->closeTransaction(trans);
8176  thd_ndb->trans= NULL;
8177  thd_ndb->m_handler= NULL;
8178 
8179  /* Clear list of tables changed by transaction */
8180  NDB_SHARE* share;
8181  List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
8182  while ((share= it++))
8183  {
8184  DBUG_PRINT("info", ("Remove share to list of changed tables, %p",
8185  share));
8186  free_share(&share);
8187  }
8188  thd_ndb->changed_tables.empty();
8189 
8190  if (thd->slave_thread)
8191  update_slave_api_stats(thd_ndb->ndb);
8192 
8193  DBUG_RETURN(res);
8194 }
8195 
8200 struct NDB_Modifier
8201 {
8202  enum { M_BOOL } m_type;
8203  const char * m_name;
8204  size_t m_name_len;
8205  bool m_found;
8206  union {
8207  bool m_val_bool;
8208 #ifdef TODO__
8209  int m_val_int;
8210  struct {
8211  const char * str;
8212  size_t len;
8213  } m_val_str;
8214 #endif
8215  };
8216 };
8217 
8218 static const
8219 struct NDB_Modifier ndb_table_modifiers[] =
8220 {
8221  { NDB_Modifier::M_BOOL, STRING_WITH_LEN("NOLOGGING"), 0, {0} },
8222  { NDB_Modifier::M_BOOL, 0, 0, 0, {0} }
8223 };
8224 
8225 static const
8226 struct NDB_Modifier ndb_column_modifiers[] =
8227 {
8228  { NDB_Modifier::M_BOOL, STRING_WITH_LEN("MAX_BLOB_PART_SIZE"), 0, {0} },
8229  { NDB_Modifier::M_BOOL, 0, 0, 0, {0} }
8230 };
8231 
8238 class NDB_Modifiers
8239 {
8240 public:
8241  NDB_Modifiers(const NDB_Modifier modifiers[]);
8242  ~NDB_Modifiers();
8243 
8247  int parse(THD* thd, const char * prefix, const char * str, size_t strlen);
8248 
8252  const NDB_Modifier * get(const char * name) const;
8253 private:
8254  uint m_len;
8255  struct NDB_Modifier * m_modifiers;
8256 
8257  int parse_modifier(THD *thd, const char * prefix,
8258  struct NDB_Modifier* m, const char * str);
8259 };
8260 
8261 static
8262 bool
8263 end_of_token(const char * str)
8264 {
8265  return str[0] == 0 || str[0] == ' ' || str[0] == ',';
8266 }
8267 
8268 NDB_Modifiers::NDB_Modifiers(const NDB_Modifier modifiers[])
8269 {
8270  for (m_len = 0; modifiers[m_len].m_name != 0; m_len++)
8271  {}
8272  m_modifiers = new NDB_Modifier[m_len];
8273  memcpy(m_modifiers, modifiers, m_len * sizeof(NDB_Modifier));
8274 }
8275 
8276 NDB_Modifiers::~NDB_Modifiers()
8277 {
8278  delete [] m_modifiers;
8279 }
8280 
8281 int
8282 NDB_Modifiers::parse_modifier(THD *thd,
8283  const char * prefix,
8284  struct NDB_Modifier* m,
8285  const char * str)
8286 {
8287  if (m->m_found)
8288  {
8289  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8290  ER_ILLEGAL_HA_CREATE_OPTION,
8291  "%s : modifier %s specified twice",
8292  prefix, m->m_name);
8293  }
8294 
8295  switch(m->m_type){
8296  case NDB_Modifier::M_BOOL:
8297  if (end_of_token(str))
8298  {
8299  m->m_val_bool = true;
8300  goto found;
8301  }
8302  if (str[0] != '=')
8303  break;
8304 
8305  str++;
8306  if (str[0] == '1' && end_of_token(str+1))
8307  {
8308  m->m_val_bool = true;
8309  goto found;
8310  }
8311 
8312  if (str[0] == '0' && end_of_token(str+1))
8313  {
8314  m->m_val_bool = false;
8315  goto found;
8316  }
8317  }
8318 
8319  {
8320  const char * end = strpbrk(str, " ,");
8321  if (end)
8322  {
8323  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8324  ER_ILLEGAL_HA_CREATE_OPTION,
8325  "%s : invalid value '%.*s' for %s",
8326  prefix, (int)(end - str), str, m->m_name);
8327  }
8328  else
8329  {
8330  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8331  ER_ILLEGAL_HA_CREATE_OPTION,
8332  "%s : invalid value '%s' for %s",
8333  prefix, str, m->m_name);
8334  }
8335  }
8336  return -1;
8337 found:
8338  m->m_found = true;
8339  return 0;
8340 }
8341 
8342 int
8343 NDB_Modifiers::parse(THD *thd,
8344  const char * prefix,
8345  const char * _source,
8346  size_t _source_len)
8347 {
8348  if (_source == 0 || _source_len == 0)
8349  return 0;
8350 
8351  const char * source = 0;
8352 
8356  for (size_t i = 0; i<_source_len; i++)
8357  {
8358  if (_source[i] == 0)
8359  {
8360  source = _source;
8361  break;
8362  }
8363  }
8364 
8365  if (source == 0)
8366  {
8370  char * tmp = new char[_source_len+1];
8371  if (tmp == 0)
8372  {
8373  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8374  ER_ILLEGAL_HA_CREATE_OPTION,
8375  "%s : unable to parse due to out of memory",
8376  prefix);
8377  return -1;
8378  }
8379  memcpy(tmp, _source, _source_len);
8380  tmp[_source_len] = 0;
8381  source = tmp;
8382  }
8383 
8384  const char * pos = source;
8385  if ((pos = strstr(pos, prefix)) == 0)
8386  {
8387  if (source != _source)
8388  delete [] source;
8389  return 0;
8390  }
8391 
8392  pos += strlen(prefix);
8393 
8394  while (pos && pos[0] != 0 && pos[0] != ' ')
8395  {
8396  const char * end = strpbrk(pos, " ,"); // end of current modifier
8397 
8398  for (uint i = 0; i < m_len; i++)
8399  {
8400  size_t l = m_modifiers[i].m_name_len;
8401  if (strncmp(pos, m_modifiers[i].m_name, l) == 0)
8402  {
8407  if (! (end_of_token(pos + l) || pos[l] == '='))
8408  goto unknown;
8409 
8410  pos += l;
8411  int res = parse_modifier(thd, prefix, m_modifiers+i, pos);
8412 
8413  if (res == -1)
8414  {
8418  }
8419 
8420  goto next;
8421  }
8422  }
8423 
8424  {
8425  unknown:
8426  if (end)
8427  {
8428  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8429  ER_ILLEGAL_HA_CREATE_OPTION,
8430  "%s : unknown modifier: %.*s",
8431  prefix, (int)(end - pos), pos);
8432  }
8433  else
8434  {
8435  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8436  ER_ILLEGAL_HA_CREATE_OPTION,
8437  "%s : unknown modifier: %s",
8438  prefix, pos);
8439  }
8440  }
8441 
8442 next:
8443  pos = end;
8444  if (pos && pos[0] == ',')
8445  pos++;
8446  }
8447 
8448  if (source != _source)
8449  delete [] source;
8450 
8451  return 0;
8452 }
8453 
8454 const NDB_Modifier *
8455 NDB_Modifiers::get(const char * name) const
8456 {
8457  for (uint i = 0; i < m_len; i++)
8458  {
8459  if (strcmp(name, m_modifiers[i].m_name) == 0)
8460  {
8461  return m_modifiers + i;
8462  }
8463  }
8464  return 0;
8465 }
8466 
8482 static bool
8483 ndb_blob_striping()
8484 {
8485 #ifndef DBUG_OFF
8486  const char* p= getenv("NDB_BLOB_STRIPING");
8487  if (p != 0 && *p != 0 && *p != '0' && *p != 'n' && *p != 'N')
8488  return true;
8489 #endif
8490  return false;
8491 }
8492 
8493 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
8494 const Uint32 OLD_NDB_MAX_TUPLE_SIZE_IN_WORDS = 2013;
8495 #else
8496 const Uint32 OLD_NDB_MAX_TUPLE_SIZE_IN_WORDS = NDB_MAX_TUPLE_SIZE_IN_WORDS;
8497 #endif
8498 
8499 static int create_ndb_column(THD *thd,
8500  NDBCOL &col,
8501  Field *field,
8502  HA_CREATE_INFO *create_info
8503 #ifndef NDB_WITHOUT_COLUMN_FORMAT
8504  , column_format_type
8505  default_format= COLUMN_FORMAT_TYPE_DEFAULT
8506 #endif
8507  )
8508 {
8509  NDBCOL::StorageType type= NDBCOL::StorageTypeMemory;
8510  bool dynamic= FALSE;
8511 
8512  char buf[MAX_ATTR_DEFAULT_VALUE_SIZE];
8513  DBUG_ENTER("create_ndb_column");
8514  // Set name
8515  if (col.setName(field->field_name))
8516  {
8517  DBUG_RETURN(my_errno= errno);
8518  }
8519  // Get char set
8520  CHARSET_INFO *cs= const_cast<CHARSET_INFO*>(field->charset());
8521  // Set type and sizes
8522  const enum enum_field_types mysql_type= field->real_type();
8523 
8524  NDB_Modifiers column_modifiers(ndb_column_modifiers);
8525  column_modifiers.parse(thd, "NDB_COLUMN=",
8526  field->comment.str,
8527  field->comment.length);
8528 
8529  const NDB_Modifier * mod_maxblob = column_modifiers.get("MAX_BLOB_PART_SIZE");
8530 
8531  {
8532  /* Clear default value (col obj is reused for whole table def) */
8533  col.setDefaultValue(NULL, 0);
8534 
8535  /* If the data nodes are capable then set native
8536  * default.
8537  */
8538  bool nativeDefaults =
8539  ! (thd &&
8540  (! ndb_native_default_support(get_thd_ndb(thd)->
8541  ndb->getMinDbNodeVersion())));
8542 
8543  if (likely( nativeDefaults ))
8544  {
8545  if ((!(field->flags & PRI_KEY_FLAG) ) &&
8546  type_supports_default_value(mysql_type))
8547  {
8548  if (!(field->flags & NO_DEFAULT_VALUE_FLAG))
8549  {
8550  my_ptrdiff_t src_offset= field->table->s->default_values
8551  - field->table->record[0];
8552  if ((! field->is_real_null(src_offset)) ||
8553  ((field->flags & NOT_NULL_FLAG)))
8554  {
8555  /* Set a non-null native default */
8556  memset(buf, 0, MAX_ATTR_DEFAULT_VALUE_SIZE);
8557  get_default_value(buf, field);
8558 
8559  /* For bit columns, default length is rounded up to
8560  nearest word, ensuring all data sent
8561  */
8562  Uint32 defaultLen = field_used_length(field);
8563  if(field->type() == MYSQL_TYPE_BIT)
8564  defaultLen = ((defaultLen + 3) /4) * 4;
8565  col.setDefaultValue(buf, defaultLen);
8566  }
8567  }
8568  }
8569  }
8570  }
8571  switch (mysql_type) {
8572  // Numeric types
8573  case MYSQL_TYPE_TINY:
8574  if (field->flags & UNSIGNED_FLAG)
8576  else
8577  col.setType(NDBCOL::Tinyint);
8578  col.setLength(1);
8579  break;
8580  case MYSQL_TYPE_SHORT:
8581  if (field->flags & UNSIGNED_FLAG)
8583  else
8585  col.setLength(1);
8586  break;
8587  case MYSQL_TYPE_LONG:
8588  if (field->flags & UNSIGNED_FLAG)
8590  else
8591  col.setType(NDBCOL::Int);
8592  col.setLength(1);
8593  break;
8594  case MYSQL_TYPE_INT24:
8595  if (field->flags & UNSIGNED_FLAG)
8597  else
8599  col.setLength(1);
8600  break;
8601  case MYSQL_TYPE_LONGLONG:
8602  if (field->flags & UNSIGNED_FLAG)
8604  else
8605  col.setType(NDBCOL::Bigint);
8606  col.setLength(1);
8607  break;
8608  case MYSQL_TYPE_FLOAT:
8609  col.setType(NDBCOL::Float);
8610  col.setLength(1);
8611  break;
8612  case MYSQL_TYPE_DOUBLE:
8613  col.setType(NDBCOL::Double);
8614  col.setLength(1);
8615  break;
8616  case MYSQL_TYPE_DECIMAL:
8617  {
8618  Field_decimal *f= (Field_decimal*)field;
8619  uint precision= f->pack_length();
8620  uint scale= f->decimals();
8621  if (field->flags & UNSIGNED_FLAG)
8622  {
8623  col.setType(NDBCOL::Olddecimalunsigned);
8624  precision-= (scale > 0);
8625  }
8626  else
8627  {
8629  precision-= 1 + (scale > 0);
8630  }
8631  col.setPrecision(precision);
8632  col.setScale(scale);
8633  col.setLength(1);
8634  }
8635  break;
8636  case MYSQL_TYPE_NEWDECIMAL:
8637  {
8639  uint precision= f->precision;
8640  uint scale= f->decimals();
8641  if (field->flags & UNSIGNED_FLAG)
8642  {
8643  col.setType(NDBCOL::Decimalunsigned);
8644  }
8645  else
8646  {
8647  col.setType(NDBCOL::Decimal);
8648  }
8649  col.setPrecision(precision);
8650  col.setScale(scale);
8651  col.setLength(1);
8652  }
8653  break;
8654  // Date types
8655  case MYSQL_TYPE_DATETIME:
8657  col.setLength(1);
8658  break;
8659  case MYSQL_TYPE_DATE: // ?
8660  col.setType(NDBCOL::Char);
8661  col.setLength(field->pack_length());
8662  break;
8663  case MYSQL_TYPE_NEWDATE:
8664  col.setType(NDBCOL::Date);
8665  col.setLength(1);
8666  break;
8667  case MYSQL_TYPE_TIME:
8668  col.setType(NDBCOL::Time);
8669  col.setLength(1);
8670  break;
8671  case MYSQL_TYPE_YEAR:
8672  col.setType(NDBCOL::Year);
8673  col.setLength(1);
8674  break;
8675  case MYSQL_TYPE_TIMESTAMP:
8677  col.setLength(1);
8678  break;
8679  // Char types
8680  case MYSQL_TYPE_STRING:
8681  if (field->pack_length() == 0)
8682  {
8683  col.setType(NDBCOL::Bit);
8684  col.setLength(1);
8685  }
8686  else if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8687  {
8688  col.setType(NDBCOL::Binary);
8689  col.setLength(field->pack_length());
8690  }
8691  else
8692  {
8693  col.setType(NDBCOL::Char);
8694  col.setCharset(cs);
8695  col.setLength(field->pack_length());
8696  }
8697  break;
8698  case MYSQL_TYPE_VAR_STRING: // ?
8699  case MYSQL_TYPE_VARCHAR:
8700  {
8701  Field_varstring* f= (Field_varstring*)field;
8702  if (f->length_bytes == 1)
8703  {
8704  if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8706  else {
8707  col.setType(NDBCOL::Varchar);
8708  col.setCharset(cs);
8709  }
8710  }
8711  else if (f->length_bytes == 2)
8712  {
8713  if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8715  else {
8717  col.setCharset(cs);
8718  }
8719  }
8720  else
8721  {
8722  DBUG_RETURN(HA_ERR_UNSUPPORTED);
8723  }
8724  col.setLength(field->field_length);
8725  }
8726  break;
8727  // Blob types (all come in as MYSQL_TYPE_BLOB)
8728  mysql_type_tiny_blob:
8729  case MYSQL_TYPE_TINY_BLOB:
8730  if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8731  col.setType(NDBCOL::Blob);
8732  else {
8733  col.setType(NDBCOL::Text);
8734  col.setCharset(cs);
8735  }
8736  col.setInlineSize(256);
8737  // No parts
8738  col.setPartSize(0);
8739  col.setStripeSize(ndb_blob_striping() ? 0 : 0);
8740  break;
8741  //mysql_type_blob:
8742  case MYSQL_TYPE_GEOMETRY:
8743  case MYSQL_TYPE_BLOB:
8744  if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8745  col.setType(NDBCOL::Blob);
8746  else {
8747  col.setType(NDBCOL::Text);
8748  col.setCharset(cs);
8749  }
8750  {
8751  Field_blob *field_blob= (Field_blob *)field;
8752  /*
8753  * max_data_length is 2^8-1, 2^16-1, 2^24-1 for tiny, blob, medium.
8754  * Tinyblob gets no blob parts. The other cases are just a crude
8755  * way to control part size and striping.
8756  *
8757  * In mysql blob(256) is promoted to blob(65535) so it does not
8758  * in fact fit "inline" in NDB.
8759  */
8760  if (field_blob->max_data_length() < (1 << 8))
8761  goto mysql_type_tiny_blob;
8762  else if (field_blob->max_data_length() < (1 << 16))
8763  {
8764  col.setInlineSize(256);
8765  col.setPartSize(2000);
8766  col.setStripeSize(ndb_blob_striping() ? 16 : 0);
8767  if (mod_maxblob->m_found)
8768  {
8769  col.setPartSize(4 * (NDB_MAX_TUPLE_SIZE_IN_WORDS - /* safty */ 13));
8770  }
8771  }
8772  else if (field_blob->max_data_length() < (1 << 24))
8773  goto mysql_type_medium_blob;
8774  else
8775  goto mysql_type_long_blob;
8776  }
8777  break;
8778  mysql_type_medium_blob:
8779  case MYSQL_TYPE_MEDIUM_BLOB:
8780  if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8781  col.setType(NDBCOL::Blob);
8782  else {
8783  col.setType(NDBCOL::Text);
8784  col.setCharset(cs);
8785  }
8786  col.setInlineSize(256);
8787  col.setPartSize(4000);
8788  col.setStripeSize(ndb_blob_striping() ? 8 : 0);
8789  if (mod_maxblob->m_found)
8790  {
8791  col.setPartSize(4 * (NDB_MAX_TUPLE_SIZE_IN_WORDS - /* safty */ 13));
8792  }
8793  break;
8794  mysql_type_long_blob:
8795  case MYSQL_TYPE_LONG_BLOB:
8796  if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
8797  col.setType(NDBCOL::Blob);
8798  else {
8799  col.setType(NDBCOL::Text);
8800  col.setCharset(cs);
8801  }
8802  col.setInlineSize(256);
8803  col.setPartSize(4 * (OLD_NDB_MAX_TUPLE_SIZE_IN_WORDS - /* safty */ 13));
8804  col.setStripeSize(ndb_blob_striping() ? 4 : 0);
8805  if (mod_maxblob->m_found)
8806  {
8807  col.setPartSize(4 * (NDB_MAX_TUPLE_SIZE_IN_WORDS - /* safty */ 13));
8808  }
8809  break;
8810  // Other types
8811  case MYSQL_TYPE_ENUM:
8812  col.setType(NDBCOL::Char);
8813  col.setLength(field->pack_length());
8814  break;
8815  case MYSQL_TYPE_SET:
8816  col.setType(NDBCOL::Char);
8817  col.setLength(field->pack_length());
8818  break;
8819  case MYSQL_TYPE_BIT:
8820  {
8821  int no_of_bits= field->field_length;
8822  col.setType(NDBCOL::Bit);
8823  if (!no_of_bits)
8824  col.setLength(1);
8825  else
8826  col.setLength(no_of_bits);
8827  break;
8828  }
8829  case MYSQL_TYPE_NULL:
8830  goto mysql_type_unsupported;
8831  mysql_type_unsupported:
8832  default:
8833  DBUG_RETURN(HA_ERR_UNSUPPORTED);
8834  }
8835  // Set nullable and pk
8836  col.setNullable(field->maybe_null());
8837  col.setPrimaryKey(field->flags & PRI_KEY_FLAG);
8838  if ((field->flags & FIELD_IN_PART_FUNC_FLAG) != 0)
8839  {
8840  col.setPartitionKey(TRUE);
8841  }
8842 
8843  // Set autoincrement
8844  if (field->flags & AUTO_INCREMENT_FLAG)
8845  {
8846 #ifndef DBUG_OFF
8847  char buff[22];
8848 #endif
8849  col.setAutoIncrement(TRUE);
8850  ulonglong value= create_info->auto_increment_value ?
8851  create_info->auto_increment_value : (ulonglong) 1;
8852  DBUG_PRINT("info", ("Autoincrement key, initial: %s", llstr(value, buff)));
8853  col.setAutoIncrementInitialValue(value);
8854  }
8855  else
8856  col.setAutoIncrement(FALSE);
8857 
8858 #ifndef NDB_WITHOUT_COLUMN_FORMAT
8859  DBUG_PRINT("info", ("storage: %u format: %u ",
8860  field->field_storage_type(),
8861  field->column_format()));
8862  switch (field->field_storage_type()) {
8863  case(HA_SM_DEFAULT):
8864  default:
8865  if (create_info->storage_media == HA_SM_DISK)
8866  type= NDBCOL::StorageTypeDisk;
8867  else
8868  type= NDBCOL::StorageTypeMemory;
8869  break;
8870  case(HA_SM_DISK):
8871  type= NDBCOL::StorageTypeDisk;
8872  break;
8873  case(HA_SM_MEMORY):
8874  type= NDBCOL::StorageTypeMemory;
8875  break;
8876  }
8877 
8878  switch (field->column_format()) {
8879  case(COLUMN_FORMAT_TYPE_FIXED):
8880  dynamic= FALSE;
8881  break;
8882  case(COLUMN_FORMAT_TYPE_DYNAMIC):
8883  dynamic= TRUE;
8884  break;
8885  case(COLUMN_FORMAT_TYPE_DEFAULT):
8886  default:
8887  if (create_info->row_type == ROW_TYPE_DEFAULT)
8888  dynamic= default_format;
8889  else
8890  dynamic= (create_info->row_type == ROW_TYPE_DYNAMIC);
8891  break;
8892  }
8893 #endif
8894  DBUG_PRINT("info", ("Column %s is declared %s", field->field_name,
8895  (dynamic) ? "dynamic" : "static"));
8896  if (type == NDBCOL::StorageTypeDisk)
8897  {
8898  if (dynamic)
8899  {
8900  DBUG_PRINT("info", ("Dynamic disk stored column %s changed to static",
8901  field->field_name));
8902  dynamic= false;
8903  }
8904 
8905 #ifndef NDB_WITHOUT_COLUMN_FORMAT
8906  if (thd && field->column_format() == COLUMN_FORMAT_TYPE_DYNAMIC)
8907  {
8908  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8909  ER_ILLEGAL_HA_CREATE_OPTION,
8910  "DYNAMIC column %s with "
8911  "STORAGE DISK is not supported, "
8912  "column will become FIXED",
8913  field->field_name);
8914  }
8915 #endif
8916  }
8917 
8918  switch (create_info->row_type) {
8919  case ROW_TYPE_FIXED:
8920  if (thd && (dynamic || field_type_forces_var_part(field->type())))
8921  {
8922  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
8923  ER_ILLEGAL_HA_CREATE_OPTION,
8924  "Row format FIXED incompatible with "
8925  "dynamic attribute %s",
8926  field->field_name);
8927  }
8928  break;
8929  case ROW_TYPE_DYNAMIC:
8930  /*
8931  Future: make columns dynamic in this case
8932  */
8933  break;
8934  default:
8935  break;
8936  }
8937 
8938  DBUG_PRINT("info", ("Format %s, Storage %s", (dynamic)?"dynamic":"fixed",(type == NDBCOL::StorageTypeDisk)?"disk":"memory"));
8939  col.setStorageType(type);
8940  col.setDynamic(dynamic);
8941 
8942  DBUG_RETURN(0);
8943 }
8944 
8945 void ha_ndbcluster::update_create_info(HA_CREATE_INFO *create_info)
8946 {
8947  DBUG_ENTER("ha_ndbcluster::update_create_info");
8948  THD *thd= current_thd;
8949  const NDBTAB *ndbtab= m_table;
8950  Ndb *ndb= check_ndb_in_thd(thd);
8951 
8952  if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
8953  {
8954  /*
8955  Find any initial auto_increment value
8956  */
8957  for (uint i= 0; i < table->s->fields; i++)
8958  {
8959  Field *field= table->field[i];
8960  if (field->flags & AUTO_INCREMENT_FLAG)
8961  {
8962  ulonglong auto_value;
8963  uint retries= NDB_AUTO_INCREMENT_RETRIES;
8964  int retry_sleep= 30; /* 30 milliseconds, transaction */
8965  for (;;)
8966  {
8967  Ndb_tuple_id_range_guard g(m_share);
8968  if (ndb->readAutoIncrementValue(ndbtab, g.range, auto_value))
8969  {
8970  if (--retries && !thd->killed &&
8972  {
8973  do_retry_sleep(retry_sleep);
8974  continue;
8975  }
8976  const NdbError err= ndb->getNdbError();
8977  sql_print_error("Error %lu in ::update_create_info(): %s",
8978  (ulong) err.code, err.message);
8979  DBUG_VOID_RETURN;
8980  }
8981  break;
8982  }
8983  if (auto_value > 1)
8984  {
8985  create_info->auto_increment_value= auto_value;
8986  }
8987  break;
8988  }
8989  }
8990  }
8991 
8992  DBUG_VOID_RETURN;
8993 }
8994 
8995 /*
8996  Create a table in NDB Cluster
8997  */
8998 static uint get_no_fragments(ulonglong max_rows)
8999 {
9000  ulonglong acc_row_size= 25 + /*safety margin*/ 2;
9001  ulonglong acc_fragment_size= 512*1024*1024;
9002  return uint((max_rows*acc_row_size)/acc_fragment_size)+1;
9003 }
9004 
9005 
9006 /*
9007  Routine to adjust default number of partitions to always be a multiple
9008  of number of nodes and never more than 4 times the number of nodes.
9009 
9010 */
9011 static
9012 bool
9013 adjusted_frag_count(Ndb* ndb,
9014  uint requested_frags,
9015  uint &reported_frags)
9016 {
9017  unsigned no_nodes= g_ndb_cluster_connection->no_db_nodes();
9018  unsigned no_replicas= no_nodes == 1 ? 1 : 2;
9019 
9020  unsigned no_threads= 1;
9021  const unsigned no_nodegroups= g_ndb_cluster_connection->max_nodegroup() + 1;
9022 
9023  {
9027  char dbname[FN_HEADLEN+1];
9028  dbname[FN_HEADLEN]= 0;
9029  strnmov(dbname, ndb->getDatabaseName(), sizeof(dbname) - 1);
9030  ndb->setDatabaseName("sys");
9031  Ndb_table_guard ndbtab_g(ndb->getDictionary(), "SYSTAB_0");
9032  const NdbDictionary::Table * tab = ndbtab_g.get_table();
9033  if (tab)
9034  {
9035  no_replicas= ndbtab_g.get_table()->getReplicaCount();
9036 
9040  {
9041  const Uint32 frags = tab->getFragmentCount();
9042  Uint32 node = 0;
9043  Uint32 cnt = 0;
9044  for (Uint32 i = 0; i<frags; i++)
9045  {
9046  Uint32 replicas[4];
9047  if (tab->getFragmentNodes(i, replicas, NDB_ARRAY_SIZE(replicas)))
9048  {
9049  if (node == replicas[0] || node == 0)
9050  {
9051  node = replicas[0];
9052  cnt ++;
9053  }
9054  }
9055  }
9056  no_threads = cnt; // No of primary replica on 1-node
9057  }
9058  }
9059  ndb->setDatabaseName(dbname);
9060  }
9061 
9062  const unsigned usable_nodes = no_replicas * no_nodegroups;
9063  const uint max_replicas = 8 * usable_nodes * no_threads;
9064 
9065  reported_frags = usable_nodes * no_threads; // Start with 1 frag per threads
9066  Uint32 replicas = reported_frags * no_replicas;
9067 
9071  while (reported_frags < requested_frags &&
9072  (replicas + usable_nodes * no_threads * no_replicas) <= max_replicas)
9073  {
9074  reported_frags += usable_nodes * no_threads;
9075  replicas += usable_nodes * no_threads * no_replicas;
9076  }
9077 
9078  return (reported_frags < requested_frags);
9079 }
9080 
9081 
9086 int ha_ndbcluster::create(const char *name,
9087  TABLE *form,
9088  HA_CREATE_INFO *create_info)
9089 {
9090  THD *thd= current_thd;
9091  NDBTAB tab;
9092  NDBCOL col;
9093  size_t pack_length, length;
9094  uint i, pk_length= 0;
9095  uchar *data= NULL, *pack_data= NULL;
9096  bool create_temporary= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
9097  bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
9098  bool is_truncate= (thd->lex->sql_command == SQLCOM_TRUNCATE);
9099  bool use_disk= FALSE;
9100  NdbDictionary::Table::SingleUserMode single_user_mode= NdbDictionary::Table::SingleUserModeLocked;
9101  bool ndb_sys_table= FALSE;
9102  int result= 0;
9104 
9105  DBUG_ENTER("ha_ndbcluster::create");
9106  DBUG_PRINT("enter", ("name: %s", name));
9107 
9108  if (create_temporary)
9109  {
9110  /*
9111  Ndb does not support temporary tables
9112  */
9113  my_errno= ER_ILLEGAL_HA_CREATE_OPTION;
9114  DBUG_PRINT("info", ("Ndb doesn't support temporary tables"));
9115  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
9116  ER_ILLEGAL_HA_CREATE_OPTION,
9117  "Ndb doesn't support temporary tables");
9118  DBUG_RETURN(my_errno);
9119  }
9120 
9121  DBUG_ASSERT(*fn_rext((char*)name) == 0);
9122  set_dbname(name);
9123  set_tabname(name);
9124 
9125  if ((my_errno= check_ndb_connection(thd)))
9126  DBUG_RETURN(my_errno);
9127 
9128  Ndb *ndb= get_ndb(thd);
9129  NDBDICT *dict= ndb->getDictionary();
9130 
9131  table= form;
9132  if (create_from_engine)
9133  {
9134  /*
9135  Table already exists in NDB and frm file has been created by
9136  caller.
9137  Do Ndb specific stuff, such as create a .ndb file
9138  */
9139  if ((my_errno= write_ndb_file(name)))
9140  DBUG_RETURN(my_errno);
9141 
9142  ndbcluster_create_binlog_setup(thd, ndb, name, strlen(name),
9143  m_dbname, m_tabname, form);
9144  DBUG_RETURN(my_errno);
9145  }
9146 
9147  Thd_ndb *thd_ndb= get_thd_ndb(thd);
9148 
9149  if (!((thd_ndb->options & TNO_NO_LOCK_SCHEMA_OP) ||
9150  thd_ndb->has_required_global_schema_lock("ha_ndbcluster::create")))
9151 
9152  DBUG_RETURN(HA_ERR_NO_CONNECTION);
9153 
9154  /*
9155  Don't allow table creation unless
9156  schema distribution table is setup
9157  ( unless it is a creation of the schema dist table itself )
9158  */
9159  if (!ndb_schema_share)
9160  {
9161  if (!(strcmp(m_dbname, NDB_REP_DB) == 0 &&
9162  strcmp(m_tabname, NDB_SCHEMA_TABLE) == 0))
9163  {
9164  DBUG_PRINT("info", ("Schema distribution table not setup"));
9165  DBUG_RETURN(HA_ERR_NO_CONNECTION);
9166  }
9167  single_user_mode = NdbDictionary::Table::SingleUserModeReadWrite;
9168  ndb_sys_table= TRUE;
9169  }
9170 
9171  if (!ndb_apply_status_share)
9172  {
9173  if ((strcmp(m_dbname, NDB_REP_DB) == 0 &&
9174  strcmp(m_tabname, NDB_APPLY_TABLE) == 0))
9175  {
9176  ndb_sys_table= TRUE;
9177  }
9178  }
9179 
9180  if (is_truncate)
9181  {
9182  Ndb_table_guard ndbtab_g(dict);
9183  ndbtab_g.init(m_tabname);
9184  if (!(m_table= ndbtab_g.get_table()))
9185  ERR_RETURN(dict->getNdbError());
9186  m_table= NULL;
9187  DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE"));
9188  if ((my_errno= delete_table(name)))
9189  DBUG_RETURN(my_errno);
9190  ndbtab_g.reinit();
9191  }
9192 
9193  NDB_Modifiers table_modifiers(ndb_table_modifiers);
9194  table_modifiers.parse(thd, "NDB_TABLE=", create_info->comment.str,
9195  create_info->comment.length);
9196  const NDB_Modifier * mod_nologging = table_modifiers.get("NOLOGGING");
9197 
9198 #ifdef HAVE_NDB_BINLOG
9199  /* Read ndb_replication entry for this table, if any */
9200  Uint32 binlog_flags;
9201  const st_conflict_fn_def* conflict_fn= NULL;
9202  st_conflict_fn_arg args[MAX_CONFLICT_ARGS];
9203  Uint32 num_args = MAX_CONFLICT_ARGS;
9204 
9205  int rep_read_rc= ndbcluster_get_binlog_replication_info(thd,
9206  ndb,
9207  m_dbname,
9208  m_tabname,
9209  ::server_id,
9210  form,
9211  &binlog_flags,
9212  &conflict_fn,
9213  args,
9214  &num_args);
9215  if (rep_read_rc != 0)
9216  {
9217  DBUG_RETURN(rep_read_rc);
9218  }
9219 
9220  /* Reset database name */
9221  ndb->setDatabaseName(m_dbname);
9222 
9223  /* Use ndb_replication information as required */
9224  if (conflict_fn != NULL)
9225  {
9226  switch(conflict_fn->type)
9227  {
9228  case CFT_NDB_EPOCH:
9229  {
9230  /* Default 6 extra Gci bits allows 2^6 == 64
9231  * epochs / saveGCP, a comfortable default
9232  */
9233  Uint32 numExtraGciBits = 6;
9234  Uint32 numExtraAuthorBits = 1;
9235 
9236  if ((num_args == 1) &&
9237  (args[0].type == CFAT_EXTRA_GCI_BITS))
9238  {
9239  numExtraGciBits = args[0].extraGciBits;
9240  }
9241  DBUG_PRINT("info", ("Setting ExtraRowGciBits to %u, "
9242  "ExtraAuthorBits to %u",
9243  numExtraGciBits,
9244  numExtraAuthorBits));
9245 
9246  tab.setExtraRowGciBits(numExtraGciBits);
9247  tab.setExtraRowAuthorBits(numExtraAuthorBits);
9248  }
9249  default:
9250  break;
9251  }
9252  }
9253 #endif
9254 
9255  if ((dict->beginSchemaTrans() == -1))
9256  {
9257  DBUG_PRINT("info", ("Failed to start schema transaction"));
9258  goto err_return;
9259  }
9260  DBUG_PRINT("info", ("Started schema transaction"));
9261 
9262  DBUG_PRINT("table", ("name: %s", m_tabname));
9263  if (tab.setName(m_tabname))
9264  {
9265  my_errno= errno;
9266  goto abort;
9267  }
9268  if (!ndb_sys_table)
9269  {
9270  if (THDVAR(thd, table_temporary))
9271  {
9272 #ifdef DOES_NOT_WORK_CURRENTLY
9273  tab.setTemporary(TRUE);
9274 #endif
9275  tab.setLogging(FALSE);
9276  }
9277  else if (THDVAR(thd, table_no_logging))
9278  {
9279  tab.setLogging(FALSE);
9280  }
9281 
9282  if (mod_nologging->m_found)
9283  {
9284  tab.setLogging(!mod_nologging->m_val_bool);
9285  }
9286  }
9287  tab.setSingleUserMode(single_user_mode);
9288 
9289  // Save frm data for this table
9290  if (readfrm(name, &data, &length))
9291  {
9292  result= 1;
9293  goto abort_return;
9294  }
9295  if (packfrm(data, length, &pack_data, &pack_length))
9296  {
9297  my_free((char*)data, MYF(0));
9298  result= 2;
9299  goto abort_return;
9300  }
9301  DBUG_PRINT("info",
9302  ("setFrm data: 0x%lx len: %lu", (long) pack_data,
9303  (ulong) pack_length));
9304  tab.setFrm(pack_data, Uint32(pack_length));
9305  my_free((char*)data, MYF(0));
9306  my_free((char*)pack_data, MYF(0));
9307 
9308  /*
9309  Handle table row type
9310 
9311  Default is to let table rows have var part reference so that online
9312  add column can be performed in the future. Explicitly setting row
9313  type to fixed will omit var part reference, which will save data
9314  memory in ndb, but at the cost of not being able to online add
9315  column to this table
9316  */
9317  switch (create_info->row_type) {
9318  case ROW_TYPE_FIXED:
9319  tab.setForceVarPart(FALSE);
9320  break;
9321  case ROW_TYPE_DYNAMIC:
9322  /* fall through, treat as default */
9323  default:
9324  /* fall through, treat as default */
9325  case ROW_TYPE_DEFAULT:
9326  tab.setForceVarPart(TRUE);
9327  break;
9328  }
9329 
9330  /*
9331  Setup columns
9332  */
9333  my_bitmap_map *old_map;
9334  {
9335  restore_record(form, s->default_values);
9336  old_map= tmp_use_all_columns(form, form->read_set);
9337  }
9338 
9339  for (i= 0; i < form->s->fields; i++)
9340  {
9341  Field *field= form->field[i];
9342  DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d",
9343  field->field_name, field->real_type(),
9344  field->pack_length()));
9345  if ((my_errno= create_ndb_column(thd, col, field, create_info)))
9346  goto abort;
9347 
9348  if (!use_disk &&
9349  col.getStorageType() == NDBCOL::StorageTypeDisk)
9350  use_disk= TRUE;
9351 
9352  if (tab.addColumn(col))
9353  {
9354  my_errno= errno;
9355  goto abort;
9356  }
9357  if (col.getPrimaryKey())
9358  pk_length += (field->pack_length() + 3) / 4;
9359  }
9360 
9361  tmp_restore_column_map(form->read_set, old_map);
9362  if (use_disk)
9363  {
9364  tab.setLogging(TRUE);
9365  tab.setTemporary(FALSE);
9366  if (create_info->tablespace)
9367  tab.setTablespaceName(create_info->tablespace);
9368  else
9369  tab.setTablespaceName("DEFAULT-TS");
9370  }
9371 
9372  // Save the table level storage media setting
9373  switch(create_info->storage_media)
9374  {
9375  case HA_SM_DISK:
9376  tab.setStorageType(NdbDictionary::Column::StorageTypeDisk);
9377  break;
9378  case HA_SM_DEFAULT:
9379  tab.setStorageType(NdbDictionary::Column::StorageTypeDefault);
9380  break;
9381  case HA_SM_MEMORY:
9382  tab.setStorageType(NdbDictionary::Column::StorageTypeMemory);
9383  break;
9384  }
9385 
9386  DBUG_PRINT("info", ("Table %s is %s stored with tablespace %s",
9387  m_tabname,
9388  (use_disk) ? "disk" : "memory",
9389  (use_disk) ? tab.getTablespaceName() : "N/A"));
9390 
9391  KEY* key_info;
9392  for (i= 0, key_info= form->key_info; i < form->s->keys; i++, key_info++)
9393  {
9394  KEY_PART_INFO *key_part= key_info->key_part;
9395  KEY_PART_INFO *end= key_part + key_info->user_defined_key_parts;
9396  for (; key_part != end; key_part++)
9397  {
9398 #ifndef NDB_WITHOUT_COLUMN_FORMAT
9399  if (key_part->field->field_storage_type() == HA_SM_DISK)
9400  {
9401  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
9402  ER_ILLEGAL_HA_CREATE_OPTION,
9403  ER(ER_ILLEGAL_HA_CREATE_OPTION),
9404  ndbcluster_hton_name,
9405  "Index on field "
9406  "declared with "
9407  "STORAGE DISK is not supported");
9408  result= HA_ERR_UNSUPPORTED;
9409  goto abort_return;
9410  }
9411 #endif
9412  tab.getColumn(key_part->fieldnr-1)->setStorageType(
9413  NdbDictionary::Column::StorageTypeMemory);
9414  }
9415  }
9416 
9417  // No primary key, create shadow key as 64 bit, auto increment
9418  if (form->s->primary_key == MAX_KEY)
9419  {
9420  DBUG_PRINT("info", ("Generating shadow key"));
9421  if (col.setName("$PK"))
9422  {
9423  my_errno= errno;
9424  goto abort;
9425  }
9427  col.setLength(1);
9428  col.setNullable(FALSE);
9429  col.setPrimaryKey(TRUE);
9430  col.setAutoIncrement(TRUE);
9431  col.setDefaultValue(NULL, 0);
9432  if (tab.addColumn(col))
9433  {
9434  my_errno= errno;
9435  goto abort;
9436  }
9437  pk_length += 2;
9438  }
9439 
9440  // Make sure that blob tables don't have too big part size
9441  for (i= 0; i < form->s->fields; i++)
9442  {
9449  // To be upgrade/downgrade safe...we currently use
9450  // old NDB_MAX_TUPLE_SIZE_IN_WORDS, unless MAX_BLOB_PART_SIZE is set
9451  switch (form->field[i]->real_type()) {
9452  case MYSQL_TYPE_GEOMETRY:
9453  case MYSQL_TYPE_BLOB:
9454  case MYSQL_TYPE_MEDIUM_BLOB:
9455  case MYSQL_TYPE_LONG_BLOB:
9456  {
9457  NdbDictionary::Column * column= tab.getColumn(i);
9458  unsigned size= pk_length + (column->getPartSize()+3)/4 + 7;
9459  unsigned ndb_max= OLD_NDB_MAX_TUPLE_SIZE_IN_WORDS;
9460  if (column->getPartSize() > (int)(4 * ndb_max))
9461  ndb_max= NDB_MAX_TUPLE_SIZE_IN_WORDS; // MAX_BLOB_PART_SIZE
9462 
9463  if (size > ndb_max &&
9464  (pk_length+7) < ndb_max)
9465  {
9466  size= ndb_max - pk_length - 7;
9467  column->setPartSize(4*size);
9468  }
9474  }
9475  default:
9476  break;
9477  }
9478  }
9479 
9480  // Check partition info
9481  if ((my_errno= set_up_partition_info(form->part_info, tab)))
9482  goto abort;
9483 
9484  if (tab.getFragmentType() == NDBTAB::HashMapPartition &&
9485  tab.getDefaultNoPartitionsFlag() &&
9486  (create_info->max_rows != 0 || create_info->min_rows != 0))
9487  {
9488  ulonglong rows= create_info->max_rows >= create_info->min_rows ?
9489  create_info->max_rows :
9490  create_info->min_rows;
9491  uint no_fragments= get_no_fragments(rows);
9492  uint reported_frags= no_fragments;
9493  if (adjusted_frag_count(ndb, no_fragments, reported_frags))
9494  {
9495  push_warning(current_thd,
9496  Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
9497  "Ndb might have problems storing the max amount "
9498  "of rows specified");
9499  }
9500  tab.setFragmentCount(reported_frags);
9501  tab.setDefaultNoPartitionsFlag(false);
9502  tab.setFragmentData(0, 0);
9503  }
9504 
9505  // Check for HashMap
9506  if (tab.getFragmentType() == NDBTAB::HashMapPartition &&
9507  tab.getDefaultNoPartitionsFlag())
9508  {
9509  tab.setFragmentCount(0);
9510  tab.setFragmentData(0, 0);
9511  }
9512  else if (tab.getFragmentType() == NDBTAB::HashMapPartition)
9513  {
9515  int res= dict->getDefaultHashMap(hm, tab.getFragmentCount());
9516  if (res == -1)
9517  {
9518  res= dict->initDefaultHashMap(hm, tab.getFragmentCount());
9519  if (res == -1)
9520  {
9521  const NdbError err= dict->getNdbError();
9522  my_errno= ndb_to_mysql_error(&err);
9523  goto abort;
9524  }
9525 
9526  res= dict->createHashMap(hm);
9527  if (res == -1)
9528  {
9529  const NdbError err= dict->getNdbError();
9530  my_errno= ndb_to_mysql_error(&err);
9531  goto abort;
9532  }
9533  }
9534  }
9535 
9536  // Create the table in NDB
9537  if (dict->createTable(tab, &objId) != 0)
9538  {
9539  const NdbError err= dict->getNdbError();
9540  my_errno= ndb_to_mysql_error(&err);
9541  goto abort;
9542  }
9543 
9544  DBUG_PRINT("info", ("Table %s/%s created successfully",
9545  m_dbname, m_tabname));
9546 
9547  // Create secondary indexes
9548  tab.assignObjId(objId);
9549  m_table= &tab;
9550  my_errno= create_indexes(thd, ndb, form);
9551  m_table= 0;
9552 
9553  if (!my_errno)
9554  {
9555  /*
9556  * All steps have succeeded, try and commit schema transaction
9557  */
9558  if (dict->endSchemaTrans() == -1)
9559  goto err_return;
9560  my_errno= write_ndb_file(name);
9561  }
9562  else
9563  {
9564 abort:
9565 /*
9566  * Some step during table creation failed, abort schema transaction
9567  */
9568  DBUG_PRINT("info", ("Aborting schema transaction due to error %i",
9569  my_errno));
9570  if (dict->endSchemaTrans(NdbDictionary::Dictionary::SchemaTransAbort)
9571  == -1)
9572  DBUG_PRINT("info", ("Failed to abort schema transaction, %i",
9573  dict->getNdbError().code));
9574  m_table= 0;
9575  DBUG_RETURN(my_errno);
9576 abort_return:
9577  DBUG_PRINT("info", ("Aborting schema transaction"));
9578  if (dict->endSchemaTrans(NdbDictionary::Dictionary::SchemaTransAbort)
9579  == -1)
9580  DBUG_PRINT("info", ("Failed to abort schema transaction, %i",
9581  dict->getNdbError().code));
9582  DBUG_RETURN(result);
9583 err_return:
9584  m_table= 0;
9585  ERR_RETURN(dict->getNdbError());
9586  }
9587 
9591  Ndb_table_guard ndbtab_g(dict, m_tabname);
9592  m_table= ndbtab_g.get_table();
9593 
9594  if (my_errno)
9595  {
9596  /*
9597  Failed to create an index,
9598  drop the table (and all it's indexes)
9599  */
9600  while (!thd->killed)
9601  {
9602  if (dict->beginSchemaTrans() == -1)
9603  goto cleanup_failed;
9604  if (dict->dropTableGlobal(*m_table))
9605  {
9606  switch (dict->getNdbError().status)
9607  {
9609  if (!thd->killed)
9610  {
9611  if (dict->endSchemaTrans(NdbDictionary::Dictionary::SchemaTransAbort)
9612  == -1)
9613  DBUG_PRINT("info", ("Failed to abort schema transaction, %i",
9614  dict->getNdbError().code));
9615  goto cleanup_failed;
9616  }
9617  break;
9618  default:
9619  break;
9620  }
9621  }
9622  if (dict->endSchemaTrans() == -1)
9623  {
9624 cleanup_failed:
9625  DBUG_PRINT("info", ("Could not cleanup failed create %i",
9626  dict->getNdbError().code));
9627  continue; // retry indefinitly
9628  }
9629  break;
9630  }
9631  m_table = 0;
9632  DBUG_RETURN(my_errno);
9633  }
9634  else // if (!my_errno)
9635  {
9636  NDB_SHARE *share= 0;
9637  pthread_mutex_lock(&ndbcluster_mutex);
9638  /*
9639  First make sure we get a "fresh" share here, not an old trailing one...
9640  */
9641  {
9642  uint length= (uint) strlen(name);
9643  if ((share= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
9644  (const uchar*) name, length)))
9645  handle_trailing_share(thd, share);
9646  }
9647  /*
9648  get a new share
9649  */
9650 
9651  /* ndb_share reference create */
9652  if (!(share= get_share(name, form, TRUE, TRUE)))
9653  {
9654  sql_print_error("NDB: allocating table share for %s failed", name);
9655  /* my_errno is set */
9656  }
9657  else
9658  {
9659  DBUG_PRINT("NDB_SHARE", ("%s binlog create use_count: %u",
9660  share->key, share->use_count));
9661  }
9662  pthread_mutex_unlock(&ndbcluster_mutex);
9663 
9664  while (!IS_TMP_PREFIX(m_tabname))
9665  {
9666 #ifdef HAVE_NDB_BINLOG
9667  if (share)
9668  {
9669  /* Set the Binlogging information we retrieved above */
9670  ndbcluster_apply_binlog_replication_info(thd,
9671  share,
9672  m_table,
9673  form,
9674  conflict_fn,
9675  args,
9676  num_args,
9677  TRUE, /* Do set binlog flags */
9678  binlog_flags);
9679  }
9680 #endif
9681  String event_name(INJECTOR_EVENT_LEN);
9682  ndb_rep_event_name(&event_name, m_dbname, m_tabname,
9683  get_binlog_full(share));
9684  int do_event_op= ndb_binlog_running;
9685 
9686  if (!ndb_schema_share &&
9687  strcmp(share->db, NDB_REP_DB) == 0 &&
9688  strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0)
9689  do_event_op= 1;
9690 
9691  /*
9692  Always create an event for the table, as other mysql servers
9693  expect it to be there.
9694  */
9695  if (!ndbcluster_create_event(thd, ndb, m_table, event_name.c_ptr(), share,
9696  share && do_event_op ? 2 : 1/* push warning */))
9697  {
9698  if (opt_ndb_extra_logging)
9699  sql_print_information("NDB Binlog: CREATE TABLE Event: %s",
9700  event_name.c_ptr());
9701  if (share &&
9702  ndbcluster_create_event_ops(thd, share,
9703  m_table, event_name.c_ptr()))
9704  {
9705  sql_print_error("NDB Binlog: FAILED CREATE TABLE event operations."
9706  " Event: %s", name);
9707  /* a warning has been issued to the client */
9708  }
9709  }
9710  /*
9711  warning has been issued if ndbcluster_create_event failed
9712  and (share && do_event_op)
9713  */
9714  if (share && !do_event_op)
9715  set_binlog_nologging(share);
9716  ndbcluster_log_schema_op(thd,
9717  thd->query(), thd->query_length(),
9718  share->db, share->table_name,
9719  m_table->getObjectId(),
9720  m_table->getObjectVersion(),
9721  (is_truncate) ?
9722  SOT_TRUNCATE_TABLE : SOT_CREATE_TABLE,
9723  NULL, NULL);
9724  break;
9725  }
9726  }
9727 
9728  m_table= 0;
9729  DBUG_RETURN(my_errno);
9730 }
9731 
9732 
9733 int ha_ndbcluster::create_index(THD *thd, const char *name, KEY *key_info,
9734  NDB_INDEX_TYPE idx_type, uint idx_no)
9735 {
9736  int error= 0;
9737  char unique_name[FN_LEN + 1];
9738  static const char* unique_suffix= "$unique";
9739  DBUG_ENTER("ha_ndbcluster::create_ordered_index");
9740  DBUG_PRINT("info", ("Creating index %u: %s", idx_no, name));
9741 
9742  if (idx_type == UNIQUE_ORDERED_INDEX || idx_type == UNIQUE_INDEX)
9743  {
9744  strxnmov(unique_name, FN_LEN, name, unique_suffix, NullS);
9745  DBUG_PRINT("info", ("Created unique index name \'%s\' for index %d",
9746  unique_name, idx_no));
9747  }
9748 
9749  switch (idx_type){
9750  case PRIMARY_KEY_INDEX:
9751  // Do nothing, already created
9752  break;
9753  case PRIMARY_KEY_ORDERED_INDEX:
9754  error= create_ordered_index(thd, name, key_info);
9755  break;
9756  case UNIQUE_ORDERED_INDEX:
9757  if (!(error= create_ordered_index(thd, name, key_info)))
9758  error= create_unique_index(thd, unique_name, key_info);
9759  break;
9760  case UNIQUE_INDEX:
9761  if (check_index_fields_not_null(key_info))
9762  {
9763  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
9764  ER_NULL_COLUMN_IN_INDEX,
9765  "Ndb does not support unique index on NULL valued attributes, index access with NULL value will become full table scan");
9766  }
9767  error= create_unique_index(thd, unique_name, key_info);
9768  break;
9769  case ORDERED_INDEX:
9770  if (key_info->algorithm == HA_KEY_ALG_HASH)
9771  {
9772  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
9773  ER_ILLEGAL_HA_CREATE_OPTION,
9774  ER(ER_ILLEGAL_HA_CREATE_OPTION),
9775  ndbcluster_hton_name,
9776  "Ndb does not support non-unique "
9777  "hash based indexes");
9778  error= HA_ERR_UNSUPPORTED;
9779  break;
9780  }
9781  error= create_ordered_index(thd, name, key_info);
9782  break;
9783  default:
9784  DBUG_ASSERT(FALSE);
9785  break;
9786  }
9787 
9788  DBUG_RETURN(error);
9789 }
9790 
9791 int ha_ndbcluster::create_ordered_index(THD *thd, const char *name,
9792  KEY *key_info)
9793 {
9794  DBUG_ENTER("ha_ndbcluster::create_ordered_index");
9795  DBUG_RETURN(create_ndb_index(thd, name, key_info, FALSE));
9796 }
9797 
9798 int ha_ndbcluster::create_unique_index(THD *thd, const char *name,
9799  KEY *key_info)
9800 {
9801 
9802  DBUG_ENTER("ha_ndbcluster::create_unique_index");
9803  DBUG_RETURN(create_ndb_index(thd, name, key_info, TRUE));
9804 }
9805 
9806 
9814 int ha_ndbcluster::create_ndb_index(THD *thd, const char *name,
9815  KEY *key_info,
9816  bool unique)
9817 {
9818  char index_name[FN_LEN + 1];
9819  Ndb *ndb= get_ndb(thd);
9821  KEY_PART_INFO *key_part= key_info->key_part;
9822  KEY_PART_INFO *end= key_part + key_info->user_defined_key_parts;
9823 
9824  DBUG_ENTER("ha_ndbcluster::create_index");
9825  DBUG_PRINT("enter", ("name: %s ", name));
9826 
9827  ndb_protect_char(name, index_name, sizeof(index_name) - 1, '/');
9828  DBUG_PRINT("info", ("index name: %s ", index_name));
9829 
9830  NdbDictionary::Index ndb_index(index_name);
9831  if (unique)
9832  ndb_index.setType(NdbDictionary::Index::UniqueHashIndex);
9833  else
9834  {
9835  ndb_index.setType(NdbDictionary::Index::OrderedIndex);
9836  // TODO Only temporary ordered indexes supported
9837  ndb_index.setLogging(FALSE);
9838  }
9839  if (!m_table->getLogging())
9840  ndb_index.setLogging(FALSE);
9841  if (((NDBTAB*)m_table)->getTemporary())
9842  ndb_index.setTemporary(TRUE);
9843  if (ndb_index.setTable(m_tabname))
9844  {
9845  DBUG_RETURN(my_errno= errno);
9846  }
9847 
9848  for (; key_part != end; key_part++)
9849  {
9850  Field *field= key_part->field;
9851 #ifndef NDB_WITHOUT_COLUMN_FORMAT
9852  if (field->field_storage_type() == HA_SM_DISK)
9853  {
9854  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
9855  ER_ILLEGAL_HA_CREATE_OPTION,
9856  ER(ER_ILLEGAL_HA_CREATE_OPTION),
9857  ndbcluster_hton_name,
9858  "Index on field "
9859  "declared with "
9860  "STORAGE DISK is not supported");
9861  DBUG_RETURN(HA_ERR_UNSUPPORTED);
9862  }
9863 #endif
9864  DBUG_PRINT("info", ("attr: %s", field->field_name));
9865  if (ndb_index.addColumnName(field->field_name))
9866  {
9867  DBUG_RETURN(my_errno= errno);
9868  }
9869  }
9870 
9871  if (dict->createIndex(ndb_index, *m_table))
9872  ERR_RETURN(dict->getNdbError());
9873 
9874  // Success
9875  DBUG_PRINT("info", ("Created index %s", name));
9876  DBUG_RETURN(0);
9877 }
9878 
9879 int ha_ndbcluster::add_index_impl(THD *thd, TABLE *table_arg,
9880  KEY *key_info, uint num_of_keys)
9881 {
9882  int error= 0;
9883  uint idx;
9884  DBUG_ENTER("ha_ndbcluster::add_index");
9885  DBUG_PRINT("enter", ("table %s", table_arg->s->table_name.str));
9886  DBUG_ASSERT(m_share->state == NSS_ALTERED);
9887 
9888  for (idx= 0; idx < num_of_keys; idx++)
9889  {
9890  KEY *key= key_info + idx;
9891  KEY_PART_INFO *key_part= key->key_part;
9892  KEY_PART_INFO *end= key_part + key->user_defined_key_parts;
9893  NDB_INDEX_TYPE idx_type= get_index_type_from_key(idx, key_info, false);
9894  DBUG_PRINT("info", ("Adding index: '%s'", key_info[idx].name));
9895  // Add fields to key_part struct
9896  for (; key_part != end; key_part++)
9897  key_part->field= table->field[key_part->fieldnr];
9898  // Check index type
9899  // Create index in ndb
9900  if((error= create_index(thd, key_info[idx].name, key, idx_type, idx)))
9901  break;
9902  }
9903  DBUG_RETURN(error);
9904 }
9905 
9910 int ha_ndbcluster::rename_table(const char *from, const char *to)
9911 {
9912  THD *thd= current_thd;
9913  NDBDICT *dict;
9914  char old_dbname[FN_HEADLEN];
9915  char new_dbname[FN_HEADLEN];
9916  char new_tabname[FN_HEADLEN];
9917  const NDBTAB *orig_tab;
9918  int result;
9919  bool recreate_indexes= FALSE;
9920  NDBDICT::List index_list;
9921 
9922  DBUG_ENTER("ha_ndbcluster::rename_table");
9923  DBUG_PRINT("info", ("Renaming %s to %s", from, to));
9924 
9925  if (thd == injector_thd)
9926  {
9927  /*
9928  Table was renamed remotely is already
9929  renamed inside ndb.
9930  Just rename .ndb file.
9931  */
9932  DBUG_RETURN(handler::rename_table(from, to));
9933  }
9934 
9935  set_dbname(from, old_dbname);
9936  set_dbname(to, new_dbname);
9937  set_tabname(from);
9938  set_tabname(to, new_tabname);
9939 
9940  if (check_ndb_connection(thd))
9941  DBUG_RETURN(my_errno= HA_ERR_NO_CONNECTION);
9942 
9943  Thd_ndb *thd_ndb= thd_get_thd_ndb(thd);
9944  if (!thd_ndb->has_required_global_schema_lock("ha_ndbcluster::rename_table"))
9945  DBUG_RETURN(HA_ERR_NO_CONNECTION);
9946 
9947  Ndb *ndb= get_ndb(thd);
9948  ndb->setDatabaseName(old_dbname);
9949  dict= ndb->getDictionary();
9950  Ndb_table_guard ndbtab_g(dict, m_tabname);
9951  if (!(orig_tab= ndbtab_g.get_table()))
9952  ERR_RETURN(dict->getNdbError());
9953 
9954  if (my_strcasecmp(system_charset_info, new_dbname, old_dbname))
9955  {
9956  dict->listIndexes(index_list, *orig_tab);
9957  recreate_indexes= TRUE;
9958  }
9959  // Change current database to that of target table
9960  set_dbname(to);
9961  if (ndb->setDatabaseName(m_dbname))
9962  {
9963  ERR_RETURN(ndb->getNdbError());
9964  }
9965 
9966  int ndb_table_id= orig_tab->getObjectId();
9967  int ndb_table_version= orig_tab->getObjectVersion();
9968  /* ndb_share reference temporary */
9969  NDB_SHARE *share= get_share(from, 0, FALSE);
9970  int is_old_table_tmpfile= IS_TMP_PREFIX(m_tabname);
9971  int is_new_table_tmpfile= IS_TMP_PREFIX(new_tabname);
9972  if (!is_new_table_tmpfile && !is_old_table_tmpfile)
9973  {
9974  /*
9975  this is a "real" rename table, i.e. not tied to an offline alter table
9976  - send new name == "to" in query field
9977  */
9978  ndbcluster_log_schema_op(thd, to, strlen(to),
9979  old_dbname, m_tabname,
9980  ndb_table_id, ndb_table_version,
9981  SOT_RENAME_TABLE_PREPARE,
9982  m_dbname, new_tabname);
9983  }
9984  if (share)
9985  {
9986  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
9987  share->key, share->use_count));
9988  ndbcluster_prepare_rename_share(share, to);
9989  int ret = ndbcluster_rename_share(thd, share);
9990  assert(ret == 0); NDB_IGNORE_VALUE(ret);
9991  }
9992 
9993  NdbDictionary::Table new_tab= *orig_tab;
9994  new_tab.setName(new_tabname);
9995  if (dict->alterTableGlobal(*orig_tab, new_tab) != 0)
9996  {
9997  NdbError ndb_error= dict->getNdbError();
9998  if (share)
9999  {
10000  int ret = ndbcluster_undo_rename_share(thd, share);
10001  assert(ret == 0); NDB_IGNORE_VALUE(ret);
10002  /* ndb_share reference temporary free */
10003  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
10004  share->key, share->use_count));
10005  free_share(&share);
10006  }
10007  ERR_RETURN(ndb_error);
10008  }
10009 
10010  // Rename .ndb file
10011  if ((result= handler::rename_table(from, to)))
10012  {
10013  // ToDo in 4.1 should rollback alter table...
10014  if (share)
10015  {
10016  /* ndb_share reference temporary free */
10017  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
10018  share->key, share->use_count));
10019  free_share(&share);
10020  }
10021  DBUG_RETURN(result);
10022  }
10023 
10024  /* handle old table */
10025  if (!is_old_table_tmpfile)
10026  {
10027  ndbcluster_drop_event(thd, ndb, share, "rename table",
10028  old_dbname, m_tabname);
10029  }
10030 
10031  if (!result && !is_new_table_tmpfile)
10032  {
10033  Ndb_table_guard ndbtab_g2(dict, new_tabname);
10034  const NDBTAB *ndbtab= ndbtab_g2.get_table();
10035 #ifdef HAVE_NDB_BINLOG
10036  if (share)
10037  ndbcluster_read_binlog_replication(thd, ndb, share, ndbtab,
10038  ::server_id, NULL, TRUE);
10039 #endif
10040  /* always create an event for the table */
10041  String event_name(INJECTOR_EVENT_LEN);
10042  ndb_rep_event_name(&event_name, new_dbname, new_tabname,
10043  get_binlog_full(share));
10044 
10045  if (!Ndb_dist_priv_util::is_distributed_priv_table(new_dbname,
10046  new_tabname) &&
10047  !ndbcluster_create_event(thd, ndb, ndbtab, event_name.c_ptr(), share,
10048  share && ndb_binlog_running ? 2 : 1/* push warning */))
10049  {
10050  if (opt_ndb_extra_logging)
10051  sql_print_information("NDB Binlog: RENAME Event: %s",
10052  event_name.c_ptr());
10053  if (share && (share->op == 0) &&
10054  ndbcluster_create_event_ops(thd, share, ndbtab, event_name.c_ptr()))
10055  {
10056  sql_print_error("NDB Binlog: FAILED create event operations "
10057  "during RENAME. Event %s", event_name.c_ptr());
10058  /* a warning has been issued to the client */
10059  }
10060  }
10061  /*
10062  warning has been issued if ndbcluster_create_event failed
10063  and (share && ndb_binlog_running)
10064  */
10065  if (!is_old_table_tmpfile)
10066  {
10067  /* "real" rename table */
10068  ndbcluster_log_schema_op(thd, thd->query(), thd->query_length(),
10069  old_dbname, m_tabname,
10070  ndb_table_id, ndb_table_version,
10071  SOT_RENAME_TABLE,
10072  m_dbname, new_tabname);
10073  }
10074  else
10075  {
10076  /* final phase of offline alter table */
10077  ndbcluster_log_schema_op(thd, thd->query(), thd->query_length(),
10078  m_dbname, new_tabname,
10079  ndb_table_id, ndb_table_version,
10080  SOT_ALTER_TABLE_COMMIT,
10081  NULL, NULL);
10082 
10083  }
10084  }
10085 
10086  // If we are moving tables between databases, we need to recreate
10087  // indexes
10088  if (recreate_indexes)
10089  {
10090  for (unsigned i = 0; i < index_list.count; i++)
10091  {
10092  NDBDICT::List::Element& index_el = index_list.elements[i];
10093  // Recreate any indexes not stored in the system database
10094  if (my_strcasecmp(system_charset_info,
10095  index_el.database, NDB_SYSTEM_DATABASE))
10096  {
10097  set_dbname(from);
10098  ndb->setDatabaseName(m_dbname);
10099  const NDBINDEX * index= dict->getIndexGlobal(index_el.name, new_tab);
10100  DBUG_PRINT("info", ("Creating index %s/%s",
10101  index_el.database, index->getName()));
10102  dict->createIndex(*index, new_tab);
10103  DBUG_PRINT("info", ("Dropping index %s/%s",
10104  index_el.database, index->getName()));
10105  set_dbname(from);
10106  ndb->setDatabaseName(m_dbname);
10107  dict->dropIndexGlobal(*index);
10108  }
10109  }
10110  }
10111  if (share)
10112  {
10113  /* ndb_share reference temporary free */
10114  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
10115  share->key, share->use_count));
10116  free_share(&share);
10117  }
10118 
10119  DBUG_RETURN(result);
10120 }
10121 
10122 
10127 static
10128 void
10129 delete_table_drop_share(NDB_SHARE* share, const char * path)
10130 {
10131  if (share)
10132  {
10133  pthread_mutex_lock(&ndbcluster_mutex);
10134 do_drop:
10135  if (share->state != NSS_DROPPED)
10136  {
10137  /*
10138  The share kept by the server has not been freed, free it
10139  */
10140  share->state= NSS_DROPPED;
10141  /* ndb_share reference create free */
10142  DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
10143  share->key, share->use_count));
10144  free_share(&share, TRUE);
10145  }
10146  /* ndb_share reference temporary free */
10147  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
10148  share->key, share->use_count));
10149  free_share(&share, TRUE);
10150  pthread_mutex_unlock(&ndbcluster_mutex);
10151  }
10152  else if (path)
10153  {
10154  pthread_mutex_lock(&ndbcluster_mutex);
10155  share= get_share(path, 0, FALSE, TRUE);
10156  if (share)
10157  {
10158  goto do_drop;
10159  }
10160  pthread_mutex_unlock(&ndbcluster_mutex);
10161  }
10162 }
10163 
10164 /* static version which does not need a handler */
10165 
10166 int
10167 ha_ndbcluster::drop_table_impl(THD *thd, ha_ndbcluster *h, Ndb *ndb,
10168  const char *path,
10169  const char *db,
10170  const char *table_name)
10171 {
10172  DBUG_ENTER("ha_ndbcluster::ndbcluster_delete_table");
10173  NDBDICT *dict= ndb->getDictionary();
10174  int ndb_table_id= 0;
10175  int ndb_table_version= 0;
10176  /*
10177  Don't allow drop table unless
10178  schema distribution table is setup
10179  */
10180  if (!ndb_schema_share)
10181  {
10182  DBUG_PRINT("info", ("Schema distribution table not setup"));
10183  DBUG_RETURN(HA_ERR_NO_CONNECTION);
10184  }
10185  /* ndb_share reference temporary */
10186  NDB_SHARE *share= get_share(path, 0, FALSE);
10187  if (share)
10188  {
10189  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
10190  share->key, share->use_count));
10191  }
10192 
10193  /* Drop the table from NDB */
10194 
10195  int res= 0;
10196  if (h && h->m_table)
10197  {
10198 retry_temporary_error1:
10199  if (dict->dropTableGlobal(*h->m_table) == 0)
10200  {
10201  ndb_table_id= h->m_table->getObjectId();
10202  ndb_table_version= h->m_table->getObjectVersion();
10203  DBUG_PRINT("info", ("success 1"));
10204  }
10205  else
10206  {
10207  switch (dict->getNdbError().status)
10208  {
10210  if (!thd->killed)
10211  goto retry_temporary_error1; // retry indefinitly
10212  break;
10213  default:
10214  break;
10215  }
10216  res= ndb_to_mysql_error(&dict->getNdbError());
10217  DBUG_PRINT("info", ("error(1) %u", res));
10218  }
10219  h->release_metadata(thd, ndb);
10220  }
10221  else
10222  {
10223  ndb->setDatabaseName(db);
10224  while (1)
10225  {
10226  Ndb_table_guard ndbtab_g(dict, table_name);
10227  if (ndbtab_g.get_table())
10228  {
10229  retry_temporary_error2:
10230  if (dict->dropTableGlobal(*ndbtab_g.get_table()) == 0)
10231  {
10232  ndb_table_id= ndbtab_g.get_table()->getObjectId();
10233  ndb_table_version= ndbtab_g.get_table()->getObjectVersion();
10234  DBUG_PRINT("info", ("success 2"));
10235  break;
10236  }
10237  else
10238  {
10239  switch (dict->getNdbError().status)
10240  {
10242  if (!thd->killed)
10243  goto retry_temporary_error2; // retry indefinitly
10244  break;
10245  default:
10246  if (dict->getNdbError().code == NDB_INVALID_SCHEMA_OBJECT)
10247  {
10248  ndbtab_g.invalidate();
10249  continue;
10250  }
10251  break;
10252  }
10253  }
10254  }
10255  res= ndb_to_mysql_error(&dict->getNdbError());
10256  DBUG_PRINT("info", ("error(2) %u", res));
10257  break;
10258  }
10259  }
10260 
10261  if (res)
10262  {
10263  /* the drop table failed for some reason, drop the share anyways */
10264  delete_table_drop_share(share, 0);
10265  DBUG_RETURN(res);
10266  }
10267 
10268  /* stop the logging of the dropped table, and cleanup */
10269 
10270  /*
10271  drop table is successful even if table does not exist in ndb
10272  and in case table was actually not dropped, there is no need
10273  to force a gcp, and setting the event_name to null will indicate
10274  that there is no event to be dropped
10275  */
10276  int table_dropped= dict->getNdbError().code != 709;
10277 
10278  {
10279  if (table_dropped)
10280  {
10281  ndbcluster_handle_drop_table(thd, ndb, share, "delete table",
10282  db, table_name);
10283  }
10284  else
10285  {
10289  ndbcluster_handle_drop_table(thd, ndb, share, "delete table",
10290  0, 0);
10291  }
10292  }
10293 
10294  if (!IS_TMP_PREFIX(table_name) && share &&
10295  thd->lex->sql_command != SQLCOM_TRUNCATE)
10296  {
10297  ndbcluster_log_schema_op(thd,
10298  thd->query(), thd->query_length(),
10299  share->db, share->table_name,
10300  ndb_table_id, ndb_table_version,
10301  SOT_DROP_TABLE, NULL, NULL);
10302  }
10303 
10304  delete_table_drop_share(share, 0);
10305  DBUG_RETURN(0);
10306 }
10307 
10308 int ha_ndbcluster::delete_table(const char *name)
10309 {
10310  THD *thd= current_thd;
10311  Thd_ndb *thd_ndb= get_thd_ndb(thd);
10312  Ndb *ndb;
10313  int error= 0;
10314  DBUG_ENTER("ha_ndbcluster::delete_table");
10315  DBUG_PRINT("enter", ("name: %s", name));
10316 
10317  if ((thd == injector_thd) ||
10318  (thd_ndb->options & TNO_NO_NDB_DROP_TABLE))
10319  {
10320  /*
10321  Table was dropped remotely is already
10322  dropped inside ndb.
10323  Just drop local files.
10324  */
10325  delete_table_drop_share(0, name);
10326  DBUG_RETURN(handler::delete_table(name));
10327  }
10328 
10329  set_dbname(name);
10330  set_tabname(name);
10331 
10332  /*
10333  Don't allow drop table unless
10334  schema distribution table is setup
10335  */
10336  if (!ndb_schema_share)
10337  {
10338  DBUG_PRINT("info", ("Schema distribution table not setup"));
10339  error= HA_ERR_NO_CONNECTION;
10340  goto err;
10341  }
10342 
10343  if (check_ndb_connection(thd))
10344  {
10345  error= HA_ERR_NO_CONNECTION;
10346  goto err;
10347  }
10348 
10349  ndb= thd_ndb->ndb;
10350 
10351  if (!thd_ndb->has_required_global_schema_lock("ha_ndbcluster::delete_table"))
10352  {
10353  error= HA_ERR_NO_CONNECTION;
10354  goto err;
10355  }
10356 
10357  /*
10358  Drop table in ndb.
10359  If it was already gone it might have been dropped
10360  remotely, give a warning and then drop .ndb file.
10361  */
10362  if (!(error= drop_table_impl(thd, this, ndb, name,
10363  m_dbname, m_tabname)) ||
10364  error == HA_ERR_NO_SUCH_TABLE)
10365  {
10366  /* Call ancestor function to delete .ndb file */
10367  int error1= handler::delete_table(name);
10368  if (!error)
10369  error= error1;
10370  }
10371 
10372 err:
10373  DBUG_RETURN(error);
10374 }
10375 
10376 
10377 void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
10378  ulonglong nb_desired_values,
10379  ulonglong *first_value,
10380  ulonglong *nb_reserved_values)
10381 {
10382  Uint64 auto_value;
10383  THD *thd= current_thd;
10384  DBUG_ENTER("get_auto_increment");
10385  DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
10386  Ndb *ndb= get_ndb(table->in_use);
10387  uint retries= NDB_AUTO_INCREMENT_RETRIES;
10388  int retry_sleep= 30; /* 30 milliseconds, transaction */
10389  for (;;)
10390  {
10391  Ndb_tuple_id_range_guard g(m_share);
10392  if ((m_skip_auto_increment &&
10393  ndb->readAutoIncrementValue(m_table, g.range, auto_value)) ||
10394  ndb->getAutoIncrementValue(m_table, g.range, auto_value,
10395  Uint32(m_autoincrement_prefetch),
10396  increment, offset))
10397  {
10398  if (--retries && !thd->killed &&
10400  {
10401  do_retry_sleep(retry_sleep);
10402  continue;
10403  }
10404  const NdbError err= ndb->getNdbError();
10405  sql_print_error("Error %lu in ::get_auto_increment(): %s",
10406  (ulong) err.code, err.message);
10407  *first_value= ~(ulonglong) 0;
10408  DBUG_VOID_RETURN;
10409  }
10410  break;
10411  }
10412  *first_value= (longlong)auto_value;
10413  /* From the point of view of MySQL, NDB reserves one row at a time */
10414  *nb_reserved_values= 1;
10415  DBUG_VOID_RETURN;
10416 }
10417 
10418 
10423 ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
10424  handler(hton, table_arg),
10425  m_thd_ndb(NULL),
10426  m_active_cursor(NULL),
10427  m_table(NULL),
10428  m_ndb_record(0),
10429  m_ndb_hidden_key_record(0),
10430  m_table_info(NULL),
10431  m_share(0),
10432  m_key_fields(NULL),
10433  m_part_info(NULL),
10434  m_user_defined_partitioning(FALSE),
10435  m_use_partition_pruning(FALSE),
10436  m_sorted(FALSE),
10437  m_use_write(FALSE),
10438  m_ignore_dup_key(FALSE),
10439  m_has_unique_index(FALSE),
10440  m_ignore_no_key(FALSE),
10441  m_read_before_write_removal_possible(FALSE),
10442  m_read_before_write_removal_used(FALSE),
10443  m_rows_updated(0),
10444  m_rows_deleted(0),
10445  m_rows_to_insert((ha_rows) 1),
10446  m_rows_inserted((ha_rows) 0),
10447  m_rows_changed((ha_rows) 0),
10448  m_delete_cannot_batch(FALSE),
10449  m_update_cannot_batch(FALSE),
10450  m_skip_auto_increment(TRUE),
10451  m_blobs_pending(0),
10452  m_is_bulk_delete(false),
10453  m_blobs_row_total_size(0),
10454  m_blobs_buffer(0),
10455  m_blobs_buffer_size(0),
10456  m_dupkey((uint) -1),
10457  m_autoincrement_prefetch(DEFAULT_AUTO_PREFETCH),
10458  m_pushed_join_member(NULL),
10459  m_pushed_join_operation(-1),
10460  m_disable_pushed_join(FALSE),
10461  m_active_query(NULL),
10462  m_pushed_operation(NULL),
10463  m_cond(NULL),
10464  m_multi_cursor(NULL)
10465 {
10466  int i;
10467 
10468  DBUG_ENTER("ha_ndbcluster");
10469 
10470  m_tabname[0]= '\0';
10471  m_dbname[0]= '\0';
10472 
10473  stats.records= ~(ha_rows)0; // uninitialized
10474  stats.block_size= 1024;
10475 
10476  for (i= 0; i < MAX_KEY; i++)
10477  ndb_init_index(m_index[i]);
10478 
10479  DBUG_VOID_RETURN;
10480 }
10481 
10482 
10487 ha_ndbcluster::~ha_ndbcluster()
10488 {
10489  THD *thd= current_thd;
10490  Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
10491  DBUG_ENTER("~ha_ndbcluster");
10492 
10493  if (m_share)
10494  {
10495  /* ndb_share reference handler free */
10496  DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
10497  m_share->key, m_share->use_count));
10498  free_share(&m_share);
10499  }
10500  release_metadata(thd, ndb);
10501  release_blobs_buffer();
10502 
10503  // Check for open cursor/transaction
10504  DBUG_ASSERT(m_thd_ndb == NULL);
10505 
10506  // Discard any generated condition
10507  DBUG_PRINT("info", ("Deleting generated condition"));
10508  if (m_cond)
10509  {
10510  delete m_cond;
10511  m_cond= NULL;
10512  }
10513  DBUG_PRINT("info", ("Deleting pushed joins"));
10514 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
10515  DBUG_ASSERT(m_active_query == NULL);
10516  DBUG_ASSERT(m_active_cursor == NULL);
10517  if (m_pushed_join_operation==PUSHED_ROOT)
10518  {
10519  delete m_pushed_join_member; // Also delete QueryDef
10520  }
10521  m_pushed_join_member= NULL;
10522 #endif
10523  DBUG_VOID_RETURN;
10524 }
10525 
10526 
10538 int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
10539 {
10540  THD *thd= current_thd;
10541  int res;
10542  KEY *key;
10543  KEY_PART_INFO *key_part_info;
10544  uint key_parts, i, j;
10545  DBUG_ENTER("ha_ndbcluster::open");
10546  DBUG_PRINT("enter", ("name: %s mode: %d test_if_locked: %d",
10547  name, mode, test_if_locked));
10548 
10549  if (table_share->primary_key != MAX_KEY)
10550  {
10551  /*
10552  Setup ref_length to make room for the whole
10553  primary key to be written in the ref variable
10554  */
10555  key= table->key_info+table_share->primary_key;
10556  ref_length= key->key_length;
10557  }
10558  else
10559  {
10560  if (m_user_defined_partitioning)
10561  {
10562  /* Add space for partid in ref */
10563  ref_length+= sizeof(m_part_id);
10564  }
10565  }
10566  DBUG_PRINT("info", ("ref_length: %d", ref_length));
10567 
10568  {
10569  char* bitmap_array;
10570  uint extra_hidden_keys= table_share->primary_key != MAX_KEY ? 0 : 1;
10571  uint n_keys= table_share->keys + extra_hidden_keys;
10572  uint ptr_size= sizeof(MY_BITMAP*) * (n_keys + 1 /* null termination */);
10573  uint map_size= sizeof(MY_BITMAP) * n_keys;
10574  m_key_fields= (MY_BITMAP**)my_malloc(ptr_size + map_size,
10575  MYF(MY_WME + MY_ZEROFILL));
10576  if (!m_key_fields)
10577  {
10578  local_close(thd, FALSE);
10579  DBUG_RETURN(1);
10580  }
10581  bitmap_array= ((char*)m_key_fields) + ptr_size;
10582  for (i= 0; i < n_keys; i++)
10583  {
10584  my_bitmap_map *bitbuf= NULL;
10585  bool is_hidden_key= (i == table_share->keys);
10586  m_key_fields[i]= (MY_BITMAP*)bitmap_array;
10587  if (is_hidden_key || (i == table_share->primary_key))
10588  {
10589  m_pk_bitmap_p= m_key_fields[i];
10590  bitbuf= m_pk_bitmap_buf;
10591  }
10592  if (bitmap_init(m_key_fields[i], bitbuf,
10593  table_share->fields, FALSE))
10594  {
10595  m_key_fields[i]= NULL;
10596  local_close(thd, FALSE);
10597  DBUG_RETURN(1);
10598  }
10599  if (!is_hidden_key)
10600  {
10601  key= table->key_info + i;
10602  key_part_info= key->key_part;
10603  key_parts= key->user_defined_key_parts;
10604  for (j= 0; j < key_parts; j++, key_part_info++)
10605  bitmap_set_bit(m_key_fields[i], key_part_info->fieldnr-1);
10606  }
10607  else
10608  {
10609  uint field_no= table_share->fields;
10610  ((uchar *)m_pk_bitmap_buf)[field_no>>3]|= (1 << (field_no & 7));
10611  }
10612  bitmap_array+= sizeof(MY_BITMAP);
10613  }
10614  m_key_fields[i]= NULL;
10615  }
10616 
10617  set_dbname(name);
10618  set_tabname(name);
10619 
10620  if ((res= check_ndb_connection(thd)) != 0)
10621  {
10622  local_close(thd, FALSE);
10623  DBUG_RETURN(res);
10624  }
10625 
10626  // Init table lock structure
10627  /* ndb_share reference handler */
10628  if ((m_share=get_share(name, table, FALSE)) == 0)
10629  {
10633  if (opt_ndb_extra_logging > 19)
10634  {
10635  sql_print_information("Calling ndbcluster_create_binlog_setup(%s) in ::open",
10636  name);
10637  }
10638  Ndb* ndb= check_ndb_in_thd(thd);
10639  ndbcluster_create_binlog_setup(thd, ndb, name, strlen(name),
10640  m_dbname, m_tabname, table);
10641  if ((m_share=get_share(name, table, FALSE)) == 0)
10642  {
10643  local_close(thd, FALSE);
10644  DBUG_RETURN(1);
10645  }
10646  }
10647 
10648  DBUG_PRINT("NDB_SHARE", ("%s handler use_count: %u",
10649  m_share->key, m_share->use_count));
10650  thr_lock_data_init(&m_share->lock,&m_lock,(void*) 0);
10651 
10652  if ((res= get_metadata(thd, name)))
10653  {
10654  local_close(thd, FALSE);
10655  DBUG_RETURN(res);
10656  }
10657 
10658  if ((res= update_stats(thd, 1, true)) ||
10659  (res= info(HA_STATUS_CONST)))
10660  {
10661  local_close(thd, TRUE);
10662  DBUG_RETURN(res);
10663  }
10664  if (ndb_binlog_is_read_only())
10665  {
10666  table->db_stat|= HA_READ_ONLY;
10667  sql_print_information("table '%s' opened read only", name);
10668  }
10669  DBUG_RETURN(0);
10670 }
10671 
10672 /*
10673  * Support for OPTIMIZE TABLE
10674  * reclaims unused space of deleted rows
10675  * and updates index statistics
10676  */
10677 int ha_ndbcluster::optimize(THD* thd, HA_CHECK_OPT* check_opt)
10678 {
10679  ulong error, stats_error= 0;
10680  const uint delay= (uint)THDVAR(thd, optimization_delay);
10681 
10682  error= ndb_optimize_table(thd, delay);
10683  stats_error= update_stats(thd, 1);
10684  return (error) ? error : stats_error;
10685 }
10686 
10687 int ha_ndbcluster::ndb_optimize_table(THD* thd, uint delay)
10688 {
10689  Thd_ndb *thd_ndb= get_thd_ndb(thd);
10690  Ndb *ndb= thd_ndb->ndb;
10691  NDBDICT *dict= ndb->getDictionary();
10692  int result=0, error= 0;
10693  uint i;
10696 
10697  DBUG_ENTER("ndb_optimize_table");
10698  if ((error= dict->optimizeTable(*m_table, th)))
10699  {
10700  DBUG_PRINT("info",
10701  ("Optimze table %s returned %d", m_tabname, error));
10702  ERR_RETURN(ndb->getNdbError());
10703  }
10704  while((result= th.next()) == 1)
10705  {
10706  if (thd->killed)
10707  DBUG_RETURN(-1);
10708  my_sleep(1000*delay);
10709  }
10710  if (result == -1 || th.close() == -1)
10711  {
10712  DBUG_PRINT("info",
10713  ("Optimize table %s did not complete", m_tabname));
10714  ERR_RETURN(ndb->getNdbError());
10715  };
10716  for (i= 0; i < MAX_KEY; i++)
10717  {
10718  if (thd->killed)
10719  DBUG_RETURN(-1);
10720  if (m_index[i].status == ACTIVE)
10721  {
10722  const NdbDictionary::Index *index= m_index[i].index;
10723  const NdbDictionary::Index *unique_index= m_index[i].unique_index;
10724 
10725  if (index)
10726  {
10727  if ((error= dict->optimizeIndex(*index, ih)))
10728  {
10729  DBUG_PRINT("info",
10730  ("Optimze index %s returned %d",
10731  index->getName(), error));
10732  ERR_RETURN(ndb->getNdbError());
10733 
10734  }
10735  while((result= ih.next()) == 1)
10736  {
10737  if (thd->killed)
10738  DBUG_RETURN(-1);
10739  my_sleep(1000*delay);
10740  }
10741  if (result == -1 || ih.close() == -1)
10742  {
10743  DBUG_PRINT("info",
10744  ("Optimize index %s did not complete", index->getName()));
10745  ERR_RETURN(ndb->getNdbError());
10746  }
10747  }
10748  if (unique_index)
10749  {
10750  if ((error= dict->optimizeIndex(*unique_index, ih)))
10751  {
10752  DBUG_PRINT("info",
10753  ("Optimze unique index %s returned %d",
10754  unique_index->getName(), error));
10755  ERR_RETURN(ndb->getNdbError());
10756  }
10757  while((result= ih.next()) == 1)
10758  {
10759  if (thd->killed)
10760  DBUG_RETURN(-1);
10761  my_sleep(1000*delay);
10762  }
10763  if (result == -1 || ih.close() == -1)
10764  {
10765  DBUG_PRINT("info",
10766  ("Optimize index %s did not complete", index->getName()));
10767  ERR_RETURN(ndb->getNdbError());
10768  }
10769  }
10770  }
10771  }
10772  DBUG_RETURN(0);
10773 }
10774 
10775 int ha_ndbcluster::analyze(THD* thd, HA_CHECK_OPT* check_opt)
10776 {
10777  int err;
10778  if ((err= update_stats(thd, 1)) != 0)
10779  return err;
10780  const bool index_stat_enable= THDVAR(NULL, index_stat_enable) &&
10781  THDVAR(thd, index_stat_enable);
10782  if (index_stat_enable)
10783  {
10784  if ((err= analyze_index(thd)) != 0)
10785  return err;
10786  }
10787  return 0;
10788 }
10789 
10790 int
10791 ha_ndbcluster::analyze_index(THD *thd)
10792 {
10793  DBUG_ENTER("ha_ndbcluster::analyze_index");
10794 
10795  Thd_ndb *thd_ndb= get_thd_ndb(thd);
10796  Ndb *ndb= thd_ndb->ndb;
10797 
10798  uint inx_list[MAX_INDEXES];
10799  uint inx_count= 0;
10800 
10801  uint inx;
10802  for (inx= 0; inx < table_share->keys; inx++)
10803  {
10804  NDB_INDEX_TYPE idx_type= get_index_type(inx);
10805 
10806  if ((idx_type == PRIMARY_KEY_ORDERED_INDEX ||
10807  idx_type == UNIQUE_ORDERED_INDEX ||
10808  idx_type == ORDERED_INDEX))
10809  {
10810  if (inx_count < MAX_INDEXES)
10811  inx_list[inx_count++]= inx;
10812  }
10813  }
10814 
10815  if (inx_count != 0)
10816  {
10817  int err= ndb_index_stat_analyze(ndb, inx_list, inx_count);
10818  if (err != 0)
10819  DBUG_RETURN(err);
10820  }
10821  DBUG_RETURN(0);
10822 }
10823 
10824 /*
10825  Set partition info
10826 
10827  SYNOPSIS
10828  set_part_info()
10829  part_info
10830 
10831  RETURN VALUE
10832  NONE
10833 
10834  DESCRIPTION
10835  Set up partition info when handler object created
10836 */
10837 
10838 void ha_ndbcluster::set_part_info(partition_info *part_info, bool early)
10839 {
10840  DBUG_ENTER("ha_ndbcluster::set_part_info");
10841  m_part_info= part_info;
10842  if (!early)
10843  {
10844  m_use_partition_pruning= FALSE;
10845  if (!(m_part_info->part_type == HASH_PARTITION &&
10846  m_part_info->list_of_part_fields &&
10847  !m_part_info->is_sub_partitioned()))
10848  {
10849  /*
10850  PARTITION BY HASH, RANGE and LIST plus all subpartitioning variants
10851  all use MySQL defined partitioning. PARTITION BY KEY uses NDB native
10852  partitioning scheme.
10853  */
10854  m_use_partition_pruning= TRUE;
10855  m_user_defined_partitioning= TRUE;
10856  }
10857  if (m_part_info->part_type == HASH_PARTITION &&
10858  m_part_info->list_of_part_fields &&
10859  partition_info_num_full_part_fields(m_part_info) == 0)
10860  {
10861  /*
10862  CREATE TABLE t (....) ENGINE NDB PARTITON BY KEY();
10863  where no primary key is defined uses a hidden key as partition field
10864  and this makes it impossible to use any partition pruning. Partition
10865  pruning requires partitioning based on real fields, also the lack of
10866  a primary key means that all accesses to tables are based on either
10867  full table scans or index scans and they can never be pruned those
10868  scans given that the hidden key is unknown. In write_row, update_row,
10869  and delete_row the normal hidden key handling will fix things.
10870  */
10871  m_use_partition_pruning= FALSE;
10872  }
10873  DBUG_PRINT("info", ("m_use_partition_pruning = %d",
10874  m_use_partition_pruning));
10875  }
10876  DBUG_VOID_RETURN;
10877 }
10878 
10884 void ha_ndbcluster::local_close(THD *thd, bool release_metadata_flag)
10885 {
10886  Ndb *ndb;
10887  DBUG_ENTER("ha_ndbcluster::local_close");
10888  if (m_key_fields)
10889  {
10890  MY_BITMAP **inx_bitmap;
10891  for (inx_bitmap= m_key_fields;
10892  (inx_bitmap != NULL) && ((*inx_bitmap) != NULL);
10893  inx_bitmap++)
10894  if ((*inx_bitmap)->bitmap != m_pk_bitmap_buf)
10895  bitmap_free(*inx_bitmap);
10896  my_free((char*)m_key_fields, MYF(0));
10897  m_key_fields= NULL;
10898  }
10899  if (m_share)
10900  {
10901  /* ndb_share reference handler free */
10902  DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
10903  m_share->key, m_share->use_count));
10904  free_share(&m_share);
10905  }
10906  m_share= 0;
10907  if (release_metadata_flag)
10908  {
10909  ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
10910  release_metadata(thd, ndb);
10911  }
10912  DBUG_VOID_RETURN;
10913 }
10914 
10915 int ha_ndbcluster::close(void)
10916 {
10917  DBUG_ENTER("close");
10918  THD *thd= table->in_use;
10919  local_close(thd, TRUE);
10920  DBUG_RETURN(0);
10921 }
10922 
10923 
10924 int ha_ndbcluster::check_ndb_connection(THD* thd)
10925 {
10926  Ndb *ndb;
10927  DBUG_ENTER("check_ndb_connection");
10928 
10929  if (!(ndb= check_ndb_in_thd(thd, true)))
10930  DBUG_RETURN(HA_ERR_NO_CONNECTION);
10931  if (ndb->setDatabaseName(m_dbname))
10932  {
10933  ERR_RETURN(ndb->getNdbError());
10934  }
10935  DBUG_RETURN(0);
10936 }
10937 
10938 
10939 static int ndbcluster_close_connection(handlerton *hton, THD *thd)
10940 {
10941  Thd_ndb *thd_ndb= get_thd_ndb(thd);
10942  DBUG_ENTER("ndbcluster_close_connection");
10943  if (thd_ndb)
10944  {
10945  Thd_ndb::release(thd_ndb);
10946  thd_set_thd_ndb(thd, NULL);
10947  }
10948  DBUG_RETURN(0);
10949 }
10950 
10951 
10956 int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
10957  const char *name,
10958  uchar **frmblob,
10959  size_t *frmlen)
10960 {
10961  int error= 0;
10962  NdbError ndb_error;
10963  size_t len;
10964  uchar* data= NULL;
10965  Ndb* ndb;
10966  char key[FN_REFLEN + 1];
10967  DBUG_ENTER("ndbcluster_discover");
10968  DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
10969 
10970  if (!(ndb= check_ndb_in_thd(thd)))
10971  DBUG_RETURN(HA_ERR_NO_CONNECTION);
10972  if (ndb->setDatabaseName(db))
10973  {
10974  ERR_RETURN(ndb->getNdbError());
10975  }
10976  NDBDICT* dict= ndb->getDictionary();
10977  build_table_filename(key, sizeof(key) - 1, db, name, "", 0);
10978  /* ndb_share reference temporary */
10979  NDB_SHARE *share= get_share(key, 0, FALSE);
10980  if (share)
10981  {
10982  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
10983  share->key, share->use_count));
10984  }
10985  if (share && get_ndb_share_state(share) == NSS_ALTERED)
10986  {
10987  // Frm has been altered on disk, but not yet written to ndb
10988  if (readfrm(key, &data, &len))
10989  {
10990  DBUG_PRINT("error", ("Could not read frm"));
10991  error= 1;
10992  goto err;
10993  }
10994  }
10995  else
10996  {
10997  Ndb_table_guard ndbtab_g(dict, name);
10998  const NDBTAB *tab= ndbtab_g.get_table();
10999  if (!tab)
11000  {
11001  const NdbError err= dict->getNdbError();
11002  if (err.code == 709 || err.code == 723)
11003  {
11004  error= -1;
11005  DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error.code));
11006  }
11007  else
11008  {
11009  error= -1;
11010  ndb_error= err;
11011  DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error.code));
11012  }
11013  goto err;
11014  }
11015  DBUG_PRINT("info", ("Found table %s", tab->getName()));
11016 
11017  len= tab->getFrmLength();
11018  if (len == 0 || tab->getFrmData() == NULL)
11019  {
11020  DBUG_PRINT("error", ("No frm data found."));
11021  error= 1;
11022  goto err;
11023  }
11024 
11025  if (unpackfrm(&data, &len, (uchar*) tab->getFrmData()))
11026  {
11027  DBUG_PRINT("error", ("Could not unpack table"));
11028  error= 1;
11029  goto err;
11030  }
11031  }
11032 #ifdef HAVE_NDB_BINLOG
11033  if (ndbcluster_check_if_local_table(db, name) &&
11034  !Ndb_dist_priv_util::is_distributed_priv_table(db, name))
11035  {
11036  DBUG_PRINT("info", ("ndbcluster_discover: Skipping locally defined table '%s.%s'",
11037  db, name));
11038  sql_print_error("ndbcluster_discover: Skipping locally defined table '%s.%s'",
11039  db, name);
11040  error= 1;
11041  goto err;
11042  }
11043 #endif
11044  *frmlen= len;
11045  *frmblob= data;
11046 
11047  if (share)
11048  {
11049  /* ndb_share reference temporary free */
11050  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
11051  share->key, share->use_count));
11052  free_share(&share);
11053  }
11054 
11055  DBUG_RETURN(0);
11056 err:
11057  my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
11058  if (share)
11059  {
11060  /* ndb_share reference temporary free */
11061  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
11062  share->key, share->use_count));
11063  free_share(&share);
11064  }
11065 
11066  if (ndb_error.code)
11067  {
11068  ERR_RETURN(ndb_error);
11069  }
11070  DBUG_RETURN(error);
11071 }
11072 
11077 int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd,
11078  const char *db,
11079  const char *name)
11080 {
11081  Ndb* ndb;
11082  DBUG_ENTER("ndbcluster_table_exists_in_engine");
11083  DBUG_PRINT("enter", ("db: %s name: %s", db, name));
11084 
11085  if (!(ndb= check_ndb_in_thd(thd)))
11086  DBUG_RETURN(HA_ERR_NO_CONNECTION);
11087  NDBDICT* dict= ndb->getDictionary();
11089  if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
11090  {
11091  ERR_RETURN(dict->getNdbError());
11092  }
11093  for (uint i= 0 ; i < list.count ; i++)
11094  {
11096  if (my_strcasecmp(table_alias_charset, elmt.database, db))
11097  continue;
11098  if (my_strcasecmp(table_alias_charset, elmt.name, name))
11099  continue;
11100  DBUG_PRINT("info", ("Found table"));
11101  DBUG_RETURN(HA_ERR_TABLE_EXIST);
11102  }
11103  DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
11104 }
11105 
11106 
11107 
11108 extern "C" uchar* tables_get_key(const char *entry, size_t *length,
11109  my_bool not_used __attribute__((unused)))
11110 {
11111  *length= strlen(entry);
11112  return (uchar*) entry;
11113 }
11114 
11115 
11122 int ndbcluster_drop_database_impl(THD *thd, const char *path)
11123 {
11124  DBUG_ENTER("ndbcluster_drop_database");
11125  char dbname[FN_HEADLEN];
11126  Ndb* ndb;
11128  uint i;
11129  char *tabname;
11130  List<char> drop_list;
11131  int ret= 0;
11132  ha_ndbcluster::set_dbname(path, (char *)&dbname);
11133  DBUG_PRINT("enter", ("db: %s", dbname));
11134 
11135  if (!(ndb= check_ndb_in_thd(thd)))
11136  DBUG_RETURN(-1);
11137 
11138  // List tables in NDB
11139  NDBDICT *dict= ndb->getDictionary();
11140  if (dict->listObjects(list,
11142  DBUG_RETURN(-1);
11143  for (i= 0 ; i < list.count ; i++)
11144  {
11146  DBUG_PRINT("info", ("Found %s/%s in NDB", elmt.database, elmt.name));
11147 
11148  // Add only tables that belongs to db
11149  // Ignore Blob part tables - they are deleted when their table
11150  // is deleted.
11151  if (my_strcasecmp(system_charset_info, elmt.database, dbname) ||
11152  IS_NDB_BLOB_PREFIX(elmt.name))
11153  continue;
11154  DBUG_PRINT("info", ("%s must be dropped", elmt.name));
11155  drop_list.push_back(thd->strdup(elmt.name));
11156  }
11157  // Drop any tables belonging to database
11158  char full_path[FN_REFLEN + 1];
11159  char *tmp= full_path +
11160  build_table_filename(full_path, sizeof(full_path) - 1, dbname, "", "", 0);
11161  if (ndb->setDatabaseName(dbname))
11162  {
11163  ERR_RETURN(ndb->getNdbError());
11164  }
11165  List_iterator_fast<char> it(drop_list);
11166  while ((tabname=it++))
11167  {
11168  tablename_to_filename(tabname, tmp, FN_REFLEN - (tmp - full_path)-1);
11169  if (ha_ndbcluster::drop_table_impl(thd, 0, ndb, full_path, dbname, tabname))
11170  {
11171  const NdbError err= dict->getNdbError();
11172  if (err.code != 709 && err.code != 723)
11173  {
11174  ret= ndb_to_mysql_error(&err);
11175  }
11176  }
11177  }
11178 
11179  dict->invalidateDbGlobal(dbname);
11180  DBUG_RETURN(ret);
11181 }
11182 
11183 static void ndbcluster_drop_database(handlerton *hton, char *path)
11184 {
11185  THD *thd= current_thd;
11186  DBUG_ENTER("ndbcluster_drop_database");
11187  /*
11188  Don't allow drop database unless
11189  schema distribution table is setup
11190  */
11191  if (!ndb_schema_share)
11192  {
11193  DBUG_PRINT("info", ("Schema distribution table not setup"));
11194  DBUG_VOID_RETURN;
11195  }
11196  ndbcluster_drop_database_impl(thd, path);
11197  char db[FN_REFLEN];
11198  ha_ndbcluster::set_dbname(path, db);
11199  uint32 table_id= 0, table_version= 0;
11200  /*
11201  Since databases aren't real ndb schema object
11202  they don't have any id/version
11203 
11204  But since that id/version is used to make sure that event's on SCHEMA_TABLE
11205  is correct, we set random numbers
11206  */
11207  table_id = (uint32)rand();
11208  table_version = (uint32)rand();
11209  ndbcluster_log_schema_op(thd,
11210  thd->query(), thd->query_length(),
11211  db, "", table_id, table_version,
11212  SOT_DROP_DB, NULL, NULL);
11213  DBUG_VOID_RETURN;
11214 }
11215 
11216 int ndb_create_table_from_engine(THD *thd, const char *db,
11217  const char *table_name)
11218 {
11219  // Copy db and table_name to stack buffers since functions used by
11220  // ha_create_table_from_engine may convert to lowercase on some platforms
11221  char db_buf[FN_REFLEN + 1];
11222  char table_name_buf[FN_REFLEN + 1];
11223  strnmov(db_buf, db, sizeof(db_buf));
11224  strnmov(table_name_buf, table_name, sizeof(table_name_buf));
11225 
11226  LEX *old_lex= thd->lex, newlex;
11227  thd->lex= &newlex;
11228  newlex.current_select= NULL;
11229  lex_start(thd);
11230  int res= ha_create_table_from_engine(thd, db_buf, table_name_buf);
11231  thd->lex= old_lex;
11232  return res;
11233 }
11234 
11235 /*
11236  find all tables in ndb and discover those needed
11237 */
11238 int ndbcluster_find_all_files(THD *thd)
11239 {
11240  Ndb* ndb;
11241  char key[FN_REFLEN + 1];
11242  NDBDICT *dict;
11243  int unhandled, retries= 5, skipped;
11244  DBUG_ENTER("ndbcluster_find_all_files");
11245 
11246  if (!(ndb= check_ndb_in_thd(thd)))
11247  DBUG_RETURN(HA_ERR_NO_CONNECTION);
11248 
11249  dict= ndb->getDictionary();
11250 
11251  LINT_INIT(unhandled);
11252  LINT_INIT(skipped);
11253  do
11254  {
11256  if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
11257  ERR_RETURN(dict->getNdbError());
11258  unhandled= 0;
11259  skipped= 0;
11260  retries--;
11261  for (uint i= 0 ; i < list.count ; i++)
11262  {
11263  NDBDICT::List::Element& elmt= list.elements[i];
11264  if (IS_TMP_PREFIX(elmt.name) || IS_NDB_BLOB_PREFIX(elmt.name))
11265  {
11266  DBUG_PRINT("info", ("Skipping %s.%s in NDB", elmt.database, elmt.name));
11267  continue;
11268  }
11269  DBUG_PRINT("info", ("Found %s.%s in NDB", elmt.database, elmt.name));
11270  if (elmt.state != NDBOBJ::StateOnline &&
11271  elmt.state != NDBOBJ::StateBackup &&
11272  elmt.state != NDBOBJ::StateBuilding)
11273  {
11274  sql_print_information("NDB: skipping setup table %s.%s, in state %d",
11275  elmt.database, elmt.name, elmt.state);
11276  skipped++;
11277  continue;
11278  }
11279 
11280  ndb->setDatabaseName(elmt.database);
11281  Ndb_table_guard ndbtab_g(dict, elmt.name);
11282  const NDBTAB *ndbtab= ndbtab_g.get_table();
11283  if (!ndbtab)
11284  {
11285  if (retries == 0)
11286  sql_print_error("NDB: failed to setup table %s.%s, error: %d, %s",
11287  elmt.database, elmt.name,
11288  dict->getNdbError().code,
11289  dict->getNdbError().message);
11290  unhandled++;
11291  continue;
11292  }
11293 
11294  if (ndbtab->getFrmLength() == 0)
11295  continue;
11296 
11297  /* check if database exists */
11298  char *end= key +
11299  build_table_filename(key, sizeof(key) - 1, elmt.database, "", "", 0);
11300  if (my_access(key, F_OK))
11301  {
11302  /* no such database defined, skip table */
11303  continue;
11304  }
11305  /* finalize construction of path */
11306  end+= tablename_to_filename(elmt.name, end,
11307  sizeof(key)-(end-key));
11308  uchar *data= 0, *pack_data= 0;
11309  size_t length, pack_length;
11310  int discover= 0;
11311  if (readfrm(key, &data, &length) ||
11312  packfrm(data, length, &pack_data, &pack_length))
11313  {
11314  discover= 1;
11315  sql_print_information("NDB: missing frm for %s.%s, discovering...",
11316  elmt.database, elmt.name);
11317  }
11318  else if (cmp_frm(ndbtab, pack_data, pack_length))
11319  {
11320  /* ndb_share reference temporary */
11321  NDB_SHARE *share= get_share(key, 0, FALSE);
11322  if (share)
11323  {
11324  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
11325  share->key, share->use_count));
11326  }
11327  if (!share || get_ndb_share_state(share) != NSS_ALTERED)
11328  {
11329  discover= 1;
11330  sql_print_information("NDB: mismatch in frm for %s.%s, discovering...",
11331  elmt.database, elmt.name);
11332  }
11333  if (share)
11334  {
11335  /* ndb_share reference temporary free */
11336  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
11337  share->key, share->use_count));
11338  free_share(&share);
11339  }
11340  }
11341  my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR));
11342  my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR));
11343 
11344  if (discover)
11345  {
11346  /* ToDo 4.1 database needs to be created if missing */
11347  if (ndb_create_table_from_engine(thd, elmt.database, elmt.name))
11348  {
11349  /* ToDo 4.1 handle error */
11350  }
11351  }
11352  else
11353  {
11354  /* set up replication for this table */
11355  ndbcluster_create_binlog_setup(thd, ndb, key, end-key,
11356  elmt.database, elmt.name,
11357  0);
11358  }
11359  }
11360  }
11361  while (unhandled && retries);
11362 
11363  DBUG_RETURN(-(skipped + unhandled));
11364 }
11365 
11366 
11367 static int
11368 ndbcluster_find_files(handlerton *hton, THD *thd,
11369  const char *db, const char *path,
11370  const char *wild, bool dir, List<LEX_STRING> *files)
11371 {
11372  DBUG_ENTER("ndbcluster_find_files");
11373  DBUG_PRINT("enter", ("db: %s", db));
11374  { // extra bracket to avoid gcc 2.95.3 warning
11375  uint i;
11376  Thd_ndb *thd_ndb;
11377  Ndb* ndb;
11378  char name[FN_REFLEN + 1];
11379  HASH ndb_tables, ok_tables;
11380  NDBDICT::List list;
11381 
11382  if (!(ndb= check_ndb_in_thd(thd)))
11383  DBUG_RETURN(HA_ERR_NO_CONNECTION);
11384  thd_ndb= get_thd_ndb(thd);
11385 
11386  if (dir)
11387  DBUG_RETURN(0); // Discover of databases not yet supported
11388 
11389  Ndb_global_schema_lock_guard ndb_global_schema_lock_guard(thd);
11390  if (ndb_global_schema_lock_guard.lock())
11391  DBUG_RETURN(HA_ERR_NO_CONNECTION);
11392 
11393  // List tables in NDB
11394  NDBDICT *dict= ndb->getDictionary();
11395  if (dict->listObjects(list,
11397  ERR_RETURN(dict->getNdbError());
11398 
11399  if (my_hash_init(&ndb_tables, table_alias_charset,list.count,0,0,
11400  (my_hash_get_key)tables_get_key,0,0))
11401  {
11402  DBUG_PRINT("error", ("Failed to init HASH ndb_tables"));
11403  DBUG_RETURN(-1);
11404  }
11405 
11406  if (my_hash_init(&ok_tables, system_charset_info,32,0,0,
11407  (my_hash_get_key)tables_get_key,0,0))
11408  {
11409  DBUG_PRINT("error", ("Failed to init HASH ok_tables"));
11410  my_hash_free(&ndb_tables);
11411  DBUG_RETURN(-1);
11412  }
11413 
11414  for (i= 0 ; i < list.count ; i++)
11415  {
11416  NDBDICT::List::Element& elmt= list.elements[i];
11417  if (IS_TMP_PREFIX(elmt.name) || IS_NDB_BLOB_PREFIX(elmt.name))
11418  {
11419  DBUG_PRINT("info", ("Skipping %s.%s in NDB", elmt.database, elmt.name));
11420  continue;
11421  }
11422  DBUG_PRINT("info", ("Found %s/%s in NDB", elmt.database, elmt.name));
11423 
11424  // Add only tables that belongs to db
11425  if (my_strcasecmp(system_charset_info, elmt.database, db))
11426  continue;
11427 
11428  // Apply wildcard to list of tables in NDB
11429  if (wild)
11430  {
11431  if (lower_case_table_names)
11432  {
11433  if (wild_case_compare(files_charset_info, elmt.name, wild))
11434  continue;
11435  }
11436  else if (wild_compare(elmt.name,wild,0))
11437  continue;
11438  }
11439  DBUG_PRINT("info", ("Inserting %s into ndb_tables hash", elmt.name));
11440  my_hash_insert(&ndb_tables, (uchar*)thd->strdup(elmt.name));
11441  }
11442 
11443  LEX_STRING *file_name;
11444  List_iterator<LEX_STRING> it(*files);
11445  List<char> delete_list;
11446  char *file_name_str;
11447  while ((file_name=it++))
11448  {
11449  bool file_on_disk= FALSE;
11450  DBUG_PRINT("info", ("%s", file_name->str));
11451  if (my_hash_search(&ndb_tables,
11452  (const uchar*)file_name->str, file_name->length))
11453  {
11454  build_table_filename(name, sizeof(name) - 1, db,
11455  file_name->str, reg_ext, 0);
11456  if (my_access(name, F_OK))
11457  {
11458  DBUG_PRINT("info", ("Table %s listed and need discovery",
11459  file_name->str));
11460  if (ndb_create_table_from_engine(thd, db, file_name->str))
11461  {
11462  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
11463  ER_TABLE_EXISTS_ERROR,
11464  "Discover of table %s.%s failed",
11465  db, file_name->str);
11466  continue;
11467  }
11468  }
11469  DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name->str));
11470  file_on_disk= TRUE;
11471  }
11472 
11473  // Check for .ndb file with this name
11474  build_table_filename(name, sizeof(name) - 1, db,
11475  file_name->str, ha_ndb_ext, 0);
11476  DBUG_PRINT("info", ("Check access for %s", name));
11477  if (my_access(name, F_OK))
11478  {
11479  DBUG_PRINT("info", ("%s did not exist on disk", name));
11480  // .ndb file did not exist on disk, another table type
11481  if (file_on_disk)
11482  {
11483  // Ignore this ndb table
11484  uchar *record= my_hash_search(&ndb_tables,
11485  (const uchar*) file_name->str,
11486  file_name->length);
11487  DBUG_ASSERT(record);
11488  my_hash_delete(&ndb_tables, record);
11489  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
11490  ER_TABLE_EXISTS_ERROR,
11491  "Local table %s.%s shadows ndb table",
11492  db, file_name->str);
11493  }
11494  continue;
11495  }
11496  if (file_on_disk)
11497  {
11498  // File existed in NDB and as frm file, put in ok_tables list
11499  my_hash_insert(&ok_tables, (uchar*) file_name->str);
11500  continue;
11501  }
11502  DBUG_PRINT("info", ("%s existed on disk", name));
11503  // The .ndb file exists on disk, but it's not in list of tables in ndb
11504  // Verify that handler agrees table is gone.
11505  if (ndbcluster_table_exists_in_engine(hton, thd, db, file_name->str) ==
11506  HA_ERR_NO_SUCH_TABLE)
11507  {
11508  DBUG_PRINT("info", ("NDB says %s does not exists", file_name->str));
11509  it.remove();
11510  // Put in list of tables to remove from disk
11511  delete_list.push_back(thd->strdup(file_name->str));
11512  }
11513  }
11514 
11515  /* setup logging to binlog for all discovered tables */
11516  {
11517  char *end, *end1= name +
11518  build_table_filename(name, sizeof(name) - 1, db, "", "", 0);
11519  for (i= 0; i < ok_tables.records; i++)
11520  {
11521  file_name_str= (char*)my_hash_element(&ok_tables, i);
11522  end= end1 +
11523  tablename_to_filename(file_name_str, end1, sizeof(name) - (end1 - name));
11524  ndbcluster_create_binlog_setup(thd, ndb, name, end-name,
11525  db, file_name_str, 0);
11526  }
11527  }
11528 
11529  // Check for new files to discover
11530  DBUG_PRINT("info", ("Checking for new files to discover"));
11531  List<char> create_list;
11532  for (i= 0 ; i < ndb_tables.records ; i++)
11533  {
11534  file_name_str= (char*) my_hash_element(&ndb_tables, i);
11535  if (!my_hash_search(&ok_tables,
11536  (const uchar*) file_name_str, strlen(file_name_str)))
11537  {
11538  build_table_filename(name, sizeof(name) - 1,
11539  db, file_name_str, reg_ext, 0);
11540  if (my_access(name, F_OK))
11541  {
11542  DBUG_PRINT("info", ("%s must be discovered", file_name_str));
11543  // File is in list of ndb tables and not in ok_tables
11544  // This table need to be created
11545  create_list.push_back(thd->strdup(file_name_str));
11546  }
11547  }
11548  }
11549 
11550 #ifndef NDB_NO_MYSQL_RM_TABLE_PART2
11551  /*
11552  Delete old files
11553 
11554  ndbcluster_find_files() may be called from I_S code and ndbcluster_binlog
11555  thread in situations when some tables are already open. This means that
11556  code below will try to obtain exclusive metadata lock on some table
11557  while holding shared meta-data lock on other tables. This might lead to a
11558  deadlock but such a deadlock should be detected by MDL deadlock detector.
11559  */
11560  List_iterator_fast<char> it3(delete_list);
11561  while ((file_name_str= it3++))
11562  {
11563  DBUG_PRINT("info", ("Removing table %s/%s", db, file_name_str));
11564  // Delete the table and all related files
11565  TABLE_LIST table_list;
11566  table_list.init_one_table(db, strlen(db),
11567  file_name_str, strlen(file_name_str),
11568  file_name_str,
11569  TL_WRITE);
11570  table_list.mdl_request.set_type(MDL_EXCLUSIVE);
11571  /*
11572  set TNO_NO_NDB_DROP_TABLE flag to not drop ndb table.
11573  it should not exist anyways
11574  */
11575  thd_ndb->options|= TNO_NO_NDB_DROP_TABLE;
11576  (void)mysql_rm_table_part2(thd, &table_list,
11577  false, /* if_exists */
11578  false, /* drop_temporary */
11579  false, /* drop_view */
11580  true /* dont_log_query*/);
11581  thd_ndb->options&= ~TNO_NO_NDB_DROP_TABLE;
11582  trans_commit_implicit(thd); /* Safety, should be unnecessary. */
11583  thd->mdl_context.release_transactional_locks();
11584  /* Clear error message that is returned when table is deleted */
11585  thd->clear_error();
11586  }
11587 #endif
11588 
11589  // Create new files
11590  List_iterator_fast<char> it2(create_list);
11591  while ((file_name_str=it2++))
11592  {
11593  DBUG_PRINT("info", ("Table %s need discovery", file_name_str));
11594  if (ndb_create_table_from_engine(thd, db, file_name_str) == 0)
11595  {
11596  LEX_STRING *tmp_file_name= 0;
11597  tmp_file_name= thd->make_lex_string(tmp_file_name, file_name_str,
11598  strlen(file_name_str), TRUE);
11599  files->push_back(tmp_file_name);
11600  }
11601  }
11602 
11603  my_hash_free(&ok_tables);
11604  my_hash_free(&ndb_tables);
11605 
11606  // Delete schema file from files
11607  if (!strcmp(db, NDB_REP_DB))
11608  {
11609  uint count = 0;
11610  while (count++ < files->elements)
11611  {
11612  file_name = (LEX_STRING *)files->pop();
11613  if (!strcmp(file_name->str, NDB_SCHEMA_TABLE))
11614  {
11615  DBUG_PRINT("info", ("skip %s.%s table, it should be hidden to user",
11616  NDB_REP_DB, NDB_SCHEMA_TABLE));
11617  continue;
11618  }
11619  files->push_back(file_name);
11620  }
11621  }
11622  } // extra bracket to avoid gcc 2.95.3 warning
11623  DBUG_RETURN(0);
11624 }
11625 
11626 
11627 /*
11628  Initialise all gloal variables before creating
11629  a NDB Cluster table handler
11630  */
11631 
11632 /* Call back after cluster connect */
11633 static int connect_callback()
11634 {
11635  pthread_mutex_lock(&LOCK_ndb_util_thread);
11636  update_status_variables(NULL, &g_ndb_status,
11637  g_ndb_cluster_connection);
11638 
11639  uint node_id, i= 0;
11641  memset((void *)g_node_id_map, 0xFFFF, sizeof(g_node_id_map));
11642  while ((node_id= g_ndb_cluster_connection->get_next_node(node_iter)))
11643  g_node_id_map[node_id]= i++;
11644 
11645  pthread_cond_signal(&COND_ndb_util_thread);
11646  pthread_mutex_unlock(&LOCK_ndb_util_thread);
11647  return 0;
11648 }
11649 
11650 #ifndef NDB_NO_WAIT_SETUP
11651 static int ndb_wait_setup_func_impl(ulong max_wait)
11652 {
11653  DBUG_ENTER("ndb_wait_setup_func_impl");
11654 
11655  pthread_mutex_lock(&ndbcluster_mutex);
11656 
11657  struct timespec abstime;
11658  set_timespec(abstime, 1);
11659 
11660  while (!ndb_setup_complete && max_wait)
11661  {
11662  int rc= pthread_cond_timedwait(&COND_ndb_setup_complete,
11663  &ndbcluster_mutex,
11664  &abstime);
11665  if (rc)
11666  {
11667  if (rc == ETIMEDOUT)
11668  {
11669  DBUG_PRINT("info", ("1s elapsed waiting"));
11670  max_wait--;
11671  set_timespec(abstime, 1); /* 1 second from now*/
11672  }
11673  else
11674  {
11675  DBUG_PRINT("info", ("Bad pthread_cond_timedwait rc : %u",
11676  rc));
11677  assert(false);
11678  break;
11679  }
11680  }
11681  }
11682 
11683  pthread_mutex_unlock(&ndbcluster_mutex);
11684 
11685  DBUG_RETURN((ndb_setup_complete == 1)? 0 : 1);
11686 }
11687 
11688 int(*ndb_wait_setup_func)(ulong) = 0;
11689 #endif
11690 extern int ndb_dictionary_is_mysqld;
11691 
11692 static int ndbcluster_init(void *p)
11693 {
11694  DBUG_ENTER("ndbcluster_init");
11695 
11696  if (ndbcluster_inited)
11697  DBUG_RETURN(FALSE);
11698 
11699  pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
11700  pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
11701  pthread_cond_init(&COND_ndb_util_thread, NULL);
11702  pthread_cond_init(&COND_ndb_util_ready, NULL);
11703  pthread_cond_init(&COND_ndb_setup_complete, NULL);
11704  ndb_util_thread_running= -1;
11705  pthread_mutex_init(&LOCK_ndb_index_stat_thread, MY_MUTEX_INIT_FAST);
11706  pthread_cond_init(&COND_ndb_index_stat_thread, NULL);
11707  pthread_cond_init(&COND_ndb_index_stat_ready, NULL);
11708  pthread_mutex_init(&ndb_index_stat_list_mutex, MY_MUTEX_INIT_FAST);
11709  pthread_mutex_init(&ndb_index_stat_stat_mutex, MY_MUTEX_INIT_FAST);
11710  pthread_cond_init(&ndb_index_stat_stat_cond, NULL);
11711  ndb_index_stat_thread_running= -1;
11712  ndbcluster_terminating= 0;
11713  ndb_dictionary_is_mysqld= 1;
11714  ndb_setup_complete= 0;
11715  ndbcluster_hton= (handlerton *)p;
11716  ndbcluster_global_schema_lock_init(ndbcluster_hton);
11717 
11718  {
11719  handlerton *h= ndbcluster_hton;
11720  h->state= SHOW_OPTION_YES;
11721  h->db_type= DB_TYPE_NDBCLUSTER;
11722  h->close_connection= ndbcluster_close_connection;
11723  h->commit= ndbcluster_commit;
11724  h->rollback= ndbcluster_rollback;
11725  h->create= ndbcluster_create_handler; /* Create a new handler */
11726  h->drop_database= ndbcluster_drop_database; /* Drop a database */
11727  h->panic= ndbcluster_end; /* Panic call */
11728  h->show_status= ndbcluster_show_status; /* Show status */
11729  h->alter_tablespace= ndbcluster_alter_tablespace; /* Show status */
11730  h->partition_flags= ndbcluster_partition_flags; /* Partition flags */
11731  h->alter_table_flags=
11732  ndbcluster_alter_table_flags; /* Alter table flags */
11733 #if MYSQL_VERSION_ID >= 50501
11734  h->fill_is_table= ndbcluster_fill_is_table;
11735 #else
11736  h->fill_files_table= ndbcluster_fill_files_table;
11737 #endif
11738  ndbcluster_binlog_init_handlerton();
11739  h->flags= HTON_CAN_RECREATE | HTON_TEMPORARY_NOT_SUPPORTED;
11740  h->discover= ndbcluster_discover;
11741  h->find_files= ndbcluster_find_files;
11742  h->table_exists_in_engine= ndbcluster_table_exists_in_engine;
11743 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
11744  h->make_pushed_join= ndbcluster_make_pushed_join;
11745 #endif
11746  }
11747 
11748  // Initialize ndb interface
11749  ndb_init_internal();
11750 
11751  /* allocate connection resources and connect to cluster */
11752  const uint global_opti_node_select= THDVAR(NULL, optimized_node_selection);
11753  if (ndbcluster_connect(connect_callback, opt_ndb_wait_connected,
11754  opt_ndb_cluster_connection_pool,
11755  (global_opti_node_select & 1),
11756  opt_ndb_connectstring,
11757  opt_ndb_nodeid))
11758  {
11759  DBUG_PRINT("error", ("Could not initiate connection to cluster"));
11760  goto ndbcluster_init_error;
11761  }
11762 
11763  (void) my_hash_init(&ndbcluster_open_tables,table_alias_charset,32,0,0,
11764  (my_hash_get_key) ndbcluster_get_key,0,0);
11765  /* start the ndb injector thread */
11766  if (ndbcluster_binlog_start())
11767  {
11768  DBUG_PRINT("error", ("Could start the injector thread"));
11769  goto ndbcluster_init_error;
11770  }
11771 
11772  // Create utility thread
11773  pthread_t tmp;
11774  if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0))
11775  {
11776  DBUG_PRINT("error", ("Could not create ndb utility thread"));
11777  my_hash_free(&ndbcluster_open_tables);
11778  pthread_mutex_destroy(&ndbcluster_mutex);
11779  pthread_mutex_destroy(&LOCK_ndb_util_thread);
11780  pthread_cond_destroy(&COND_ndb_util_thread);
11781  pthread_cond_destroy(&COND_ndb_util_ready);
11782  pthread_cond_destroy(&COND_ndb_setup_complete);
11783  goto ndbcluster_init_error;
11784  }
11785 
11786  /* Wait for the util thread to start */
11787  pthread_mutex_lock(&LOCK_ndb_util_thread);
11788  while (ndb_util_thread_running < 0)
11789  pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
11790  pthread_mutex_unlock(&LOCK_ndb_util_thread);
11791 
11792  if (!ndb_util_thread_running)
11793  {
11794  DBUG_PRINT("error", ("ndb utility thread exited prematurely"));
11795  my_hash_free(&ndbcluster_open_tables);
11796  pthread_mutex_destroy(&ndbcluster_mutex);
11797  pthread_mutex_destroy(&LOCK_ndb_util_thread);
11798  pthread_cond_destroy(&COND_ndb_util_thread);
11799  pthread_cond_destroy(&COND_ndb_util_ready);
11800  pthread_cond_destroy(&COND_ndb_setup_complete);
11801  goto ndbcluster_init_error;
11802  }
11803 
11804  // Create index statistics thread
11805  pthread_t tmp2;
11806  if (pthread_create(&tmp2, &connection_attrib, ndb_index_stat_thread_func, 0))
11807  {
11808  DBUG_PRINT("error", ("Could not create ndb index statistics thread"));
11809  my_hash_free(&ndbcluster_open_tables);
11810  pthread_mutex_destroy(&ndbcluster_mutex);
11811  pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
11812  pthread_cond_destroy(&COND_ndb_index_stat_thread);
11813  pthread_cond_destroy(&COND_ndb_index_stat_ready);
11814  pthread_mutex_destroy(&ndb_index_stat_list_mutex);
11815  pthread_mutex_destroy(&ndb_index_stat_stat_mutex);
11816  pthread_cond_destroy(&ndb_index_stat_stat_cond);
11817  goto ndbcluster_init_error;
11818  }
11819 
11820  /* Wait for the index statistics thread to start */
11821  pthread_mutex_lock(&LOCK_ndb_index_stat_thread);
11822  while (ndb_index_stat_thread_running < 0)
11823  pthread_cond_wait(&COND_ndb_index_stat_ready, &LOCK_ndb_index_stat_thread);
11824  pthread_mutex_unlock(&LOCK_ndb_index_stat_thread);
11825 
11826  if (!ndb_index_stat_thread_running)
11827  {
11828  DBUG_PRINT("error", ("ndb index statistics thread exited prematurely"));
11829  my_hash_free(&ndbcluster_open_tables);
11830  pthread_mutex_destroy(&ndbcluster_mutex);
11831  pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
11832  pthread_cond_destroy(&COND_ndb_index_stat_thread);
11833  pthread_cond_destroy(&COND_ndb_index_stat_ready);
11834  pthread_mutex_destroy(&ndb_index_stat_list_mutex);
11835  pthread_mutex_destroy(&ndb_index_stat_stat_mutex);
11836  pthread_cond_destroy(&ndb_index_stat_stat_cond);
11837  goto ndbcluster_init_error;
11838  }
11839 
11840 #ifndef NDB_NO_WAIT_SETUP
11841  ndb_wait_setup_func= ndb_wait_setup_func_impl;
11842 #endif
11843 
11844  memset(&g_slave_api_client_stats, 0, sizeof(g_slave_api_client_stats));
11845 
11846  ndbcluster_inited= 1;
11847  DBUG_RETURN(FALSE);
11848 
11849 ndbcluster_init_error:
11850  /* disconnect from cluster and free connection resources */
11851  ndbcluster_disconnect();
11852  ndbcluster_hton->state= SHOW_OPTION_DISABLED; // If we couldn't use handler
11853 
11854  ndbcluster_global_schema_lock_deinit();
11855 
11856  DBUG_RETURN(TRUE);
11857 }
11858 
11859 #ifndef DBUG_OFF
11860 static
11861 const char*
11862 get_share_state_string(NDB_SHARE_STATE s)
11863 {
11864  switch(s) {
11865  case NSS_INITIAL:
11866  return "NSS_INITIAL";
11867  case NSS_ALTERED:
11868  return "NSS_ALTERED";
11869  case NSS_DROPPED:
11870  return "NSS_DROPPED";
11871  }
11872  assert(false);
11873  return "<unknown>";
11874 }
11875 #endif
11876 
11877 int ndbcluster_binlog_end(THD *thd);
11878 
11879 static int ndbcluster_end(handlerton *hton, ha_panic_function type)
11880 {
11881  DBUG_ENTER("ndbcluster_end");
11882 
11883  if (!ndbcluster_inited)
11884  DBUG_RETURN(0);
11885  ndbcluster_inited= 0;
11886 
11887  /* wait for index stat thread to finish */
11888  sql_print_information("Stopping Cluster Index Statistics thread");
11889  pthread_mutex_lock(&LOCK_ndb_index_stat_thread);
11890  ndbcluster_terminating= 1;
11891  pthread_cond_signal(&COND_ndb_index_stat_thread);
11892  while (ndb_index_stat_thread_running > 0)
11893  pthread_cond_wait(&COND_ndb_index_stat_ready, &LOCK_ndb_index_stat_thread);
11894  pthread_mutex_unlock(&LOCK_ndb_index_stat_thread);
11895 
11896  /* wait for util and binlog thread to finish */
11897  ndbcluster_binlog_end(NULL);
11898 
11899  {
11900  pthread_mutex_lock(&ndbcluster_mutex);
11901  uint save = ndbcluster_open_tables.records; (void)save;
11902  while (ndbcluster_open_tables.records)
11903  {
11904  NDB_SHARE *share=
11905  (NDB_SHARE*) my_hash_element(&ndbcluster_open_tables, 0);
11906 #ifndef DBUG_OFF
11907  fprintf(stderr,
11908  "NDB: table share %s with use_count %d state: %s(%u) not freed\n",
11909  share->key, share->use_count,
11910  get_share_state_string(share->state),
11911  (uint)share->state);
11912 #endif
11913  ndbcluster_real_free_share(&share);
11914  }
11915  pthread_mutex_unlock(&ndbcluster_mutex);
11916  DBUG_ASSERT(save == 0);
11917  }
11918  my_hash_free(&ndbcluster_open_tables);
11919 
11920  ndb_index_stat_end();
11921  ndbcluster_disconnect();
11922 
11923  ndbcluster_global_schema_lock_deinit();
11924 
11925  // cleanup ndb interface
11926  ndb_end_internal();
11927 
11928  pthread_mutex_destroy(&ndbcluster_mutex);
11929  pthread_mutex_destroy(&LOCK_ndb_util_thread);
11930  pthread_cond_destroy(&COND_ndb_util_thread);
11931  pthread_cond_destroy(&COND_ndb_util_ready);
11932  pthread_cond_destroy(&COND_ndb_setup_complete);
11933  pthread_mutex_destroy(&LOCK_ndb_index_stat_thread);
11934  pthread_cond_destroy(&COND_ndb_index_stat_thread);
11935  pthread_cond_destroy(&COND_ndb_index_stat_ready);
11936 
11937  DBUG_RETURN(0);
11938 }
11939 
11940 void ha_ndbcluster::print_error(int error, myf errflag)
11941 {
11942  DBUG_ENTER("ha_ndbcluster::print_error");
11943  DBUG_PRINT("enter", ("error: %d", error));
11944 
11945  if (error == HA_ERR_NO_PARTITION_FOUND)
11946  m_part_info->print_no_partition_found(table);
11947  else
11948  {
11949  if (error == HA_ERR_FOUND_DUPP_KEY &&
11950  (table == NULL || table->file == NULL))
11951  {
11952  /*
11953  This is a sideffect of 'ndbcluster_print_error' (called from
11954  'ndbcluster_commit' and 'ndbcluster_rollback') which realises
11955  that it "knows nothing" and creates a brand new ha_ndbcluster
11956  in order to be able to call the print_error() function.
11957  Unfortunately the new ha_ndbcluster hasn't been open()ed
11958  and thus table pointer etc. is not set. Since handler::print_error()
11959  will use that pointer without checking for NULL(it naturally
11960  assumes an error can only be returned when the handler is open)
11961  this would crash the mysqld unless it's handled here.
11962  */
11963  my_error(ER_DUP_KEY, errflag, table_share->table_name.str, error);
11964  DBUG_VOID_RETURN;
11965  }
11966 
11967  handler::print_error(error, errflag);
11968  }
11969  DBUG_VOID_RETURN;
11970 }
11971 
11972 
11978 void ndbcluster_print_error(int error, const NdbOperation *error_op)
11979 {
11980  DBUG_ENTER("ndbcluster_print_error");
11981  TABLE_SHARE share;
11982  const char *tab_name= (error_op) ? error_op->getTableName() : "";
11983  if (tab_name == NULL)
11984  {
11985  DBUG_ASSERT(tab_name != NULL);
11986  tab_name= "";
11987  }
11988  share.db.str= (char*) "";
11989  share.db.length= 0;
11990  share.table_name.str= (char *) tab_name;
11991  share.table_name.length= strlen(tab_name);
11992  ha_ndbcluster error_handler(ndbcluster_hton, &share);
11993  error_handler.print_error(error, MYF(0));
11994  DBUG_VOID_RETURN;
11995 }
11996 
12001 void ha_ndbcluster::set_dbname(const char *path_name, char *dbname)
12002 {
12003  char *end, *ptr, *tmp_name;
12004  char tmp_buff[FN_REFLEN + 1];
12005 
12006  tmp_name= tmp_buff;
12007  /* Scan name from the end */
12008  ptr= strend(path_name)-1;
12009  while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
12010  ptr--;
12011  }
12012  ptr--;
12013  end= ptr;
12014  while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
12015  ptr--;
12016  }
12017  uint name_len= end - ptr;
12018  memcpy(tmp_name, ptr + 1, name_len);
12019  tmp_name[name_len]= '\0';
12020  filename_to_tablename(tmp_name, dbname, sizeof(tmp_buff) - 1);
12021 }
12022 
12027 void ha_ndbcluster::set_dbname(const char *path_name)
12028 {
12029  set_dbname(path_name, m_dbname);
12030 }
12031 
12036 void
12037 ha_ndbcluster::set_tabname(const char *path_name, char * tabname)
12038 {
12039  char *end, *ptr, *tmp_name;
12040  char tmp_buff[FN_REFLEN + 1];
12041 
12042  tmp_name= tmp_buff;
12043  /* Scan name from the end */
12044  end= strend(path_name)-1;
12045  ptr= end;
12046  while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
12047  ptr--;
12048  }
12049  uint name_len= end - ptr;
12050  memcpy(tmp_name, ptr + 1, end - ptr);
12051  tmp_name[name_len]= '\0';
12052  filename_to_tablename(tmp_name, tabname, sizeof(tmp_buff) - 1);
12053 }
12054 
12059 void ha_ndbcluster::set_tabname(const char *path_name)
12060 {
12061  set_tabname(path_name, m_tabname);
12062 }
12063 
12064 
12065 /*
12066  If there are no stored stats, should we do a tree-dive on all db
12067  nodes. The result is fairly good but does mean a round-trip.
12068  */
12069 static const bool g_ndb_records_in_range_tree_dive= false;
12070 
12071 /* Determine roughly how many records are in the range specified */
12072 ha_rows
12073 ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
12074  key_range *max_key)
12075 {
12076  KEY *key_info= table->key_info + inx;
12077  uint key_length= key_info->key_length;
12078  NDB_INDEX_TYPE idx_type= get_index_type(inx);
12079 
12080  DBUG_ENTER("records_in_range");
12081  // Prevent partial read of hash indexes by returning HA_POS_ERROR
12082  if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) &&
12083  ((min_key && min_key->length < key_length) ||
12084  (max_key && max_key->length < key_length)))
12085  DBUG_RETURN(HA_POS_ERROR);
12086 
12087  // Read from hash index with full key
12088  // This is a "const" table which returns only one record!
12089  if ((idx_type != ORDERED_INDEX) &&
12090  ((min_key && min_key->length == key_length) &&
12091  (max_key && max_key->length == key_length) &&
12092  (min_key->key==max_key->key ||
12093  memcmp(min_key->key, max_key->key, key_length)==0)))
12094  DBUG_RETURN(1);
12095 
12096  // XXX why this if
12097  if ((idx_type == PRIMARY_KEY_ORDERED_INDEX ||
12098  idx_type == UNIQUE_ORDERED_INDEX ||
12099  idx_type == ORDERED_INDEX))
12100  {
12101  THD *thd= current_thd;
12102  const bool index_stat_enable= THDVAR(NULL, index_stat_enable) &&
12103  THDVAR(thd, index_stat_enable);
12104 
12105  if (index_stat_enable)
12106  {
12107  ha_rows rows= HA_POS_ERROR;
12108  int err= ndb_index_stat_get_rir(inx, min_key, max_key, &rows);
12109  if (err == 0)
12110  {
12115  if (rows < 2)
12116  rows = 2;
12117  DBUG_RETURN(rows);
12118  }
12119  if (err != 0 &&
12120  /* no stats is not unexpected error */
12121  err != NdbIndexStat::NoIndexStats &&
12122  /* warning was printed at first error */
12123  err != Ndb_index_stat_error_HAS_ERROR)
12124  {
12125  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
12126  ER_CANT_GET_STAT, /* pun? */
12127  "index stats (RIR) for key %s:"
12128  " unexpected error %d",
12129  key_info->name, err);
12130  }
12131  /*fall through*/
12132  }
12133 
12134  if (g_ndb_records_in_range_tree_dive)
12135  {
12136  NDB_INDEX_DATA& d=m_index[inx];
12137  const NDBINDEX* index= d.index;
12138  Ndb *ndb= get_ndb(thd);
12139  NdbTransaction* active_trans= m_thd_ndb ? m_thd_ndb->trans : 0;
12140  NdbTransaction* trans=NULL;
12141  int res=0;
12142  Uint64 rows;
12143 
12144  do
12145  {
12146  if ((trans=active_trans) == NULL ||
12148  {
12149  DBUG_PRINT("info", ("no active trans"));
12150  if (! (trans=ndb->startTransaction()))
12151  ERR_BREAK(ndb->getNdbError(), res);
12152  }
12153 
12154  /* Create an IndexBound struct for the keys */
12156  compute_index_bounds(ib,
12157  key_info,
12158  min_key,
12159  max_key,
12160  0);
12161 
12162  ib.range_no= 0;
12163 
12164  NdbIndexStat is;
12165  if (is.records_in_range(index,
12166  trans,
12167  d.ndb_record_key,
12168  m_ndb_record,
12169  &ib,
12170  0,
12171  &rows,
12172  0) == -1)
12173  ERR_BREAK(is.getNdbError(), res);
12174  } while (0);
12175 
12176  if (trans != active_trans && rows == 0)
12177  rows = 1;
12178  if (trans != active_trans && trans != NULL)
12179  ndb->closeTransaction(trans);
12180  if (res == 0)
12181  DBUG_RETURN(rows);
12182  /*fall through*/
12183  }
12184  }
12185 
12186  /* Use simple heuristics to estimate fraction
12187  of 'stats.record' returned from range.
12188  */
12189  do
12190  {
12191  if (stats.records == ~(ha_rows)0 || stats.records == 0)
12192  {
12193  /* Refresh statistics, only read from datanodes if 'use_exact_count' */
12194  THD *thd= current_thd;
12195  if (update_stats(thd, THDVAR(thd, use_exact_count)))
12196  break;
12197  }
12198 
12199  Uint64 rows;
12200  Uint64 table_rows= stats.records;
12201  size_t eq_bound_len= 0;
12202  size_t min_key_length= (min_key) ? min_key->length : 0;
12203  size_t max_key_length= (max_key) ? max_key->length : 0;
12204 
12205  // Might have an closed/open range bound:
12206  // Low range open
12207  if (!min_key_length)
12208  {
12209  rows= (!max_key_length)
12210  ? table_rows // No range was specified
12211  : table_rows/10; // -oo .. <high range> -> 10% selectivity
12212  }
12213  // High range open
12214  else if (!max_key_length)
12215  {
12216  rows= table_rows/10; // <low range>..oo -> 10% selectivity
12217  }
12218  else
12219  {
12220  size_t bounds_len= MIN(min_key_length,max_key_length);
12221  uint eq_bound_len= 0;
12222  uint eq_bound_offs= 0;
12223 
12224  KEY_PART_INFO* key_part= key_info->key_part;
12225  KEY_PART_INFO* end= key_part+key_info->user_defined_key_parts;
12226  for (; key_part != end; key_part++)
12227  {
12228  uint part_length= key_part->store_length;
12229  if (eq_bound_offs+part_length > bounds_len ||
12230  memcmp(&min_key->key[eq_bound_offs],
12231  &max_key->key[eq_bound_offs],
12232  part_length))
12233  {
12234  break;
12235  }
12236  eq_bound_len+= key_part->length;
12237  eq_bound_offs+= part_length;
12238  }
12239 
12240  if (!eq_bound_len)
12241  {
12242  rows= table_rows/20; // <low range>..<high range> -> 5%
12243  }
12244  else
12245  {
12246  // Has an equality range on a leading part of 'key_length':
12247  // - Assume reduced selectivity for non-unique indexes
12248  // by decreasing 'eq_fraction' by 20%
12249  // - Assume equal selectivity for all eq_parts in key.
12250 
12251  double eq_fraction = (double)(eq_bound_len) / key_length;
12252  if (idx_type == ORDERED_INDEX) // Non-unique index -> less selectivity
12253  eq_fraction/= 1.20;
12254  if (eq_fraction >= 1.0) // Exact match -> 1 row
12255  DBUG_RETURN(1);
12256 
12257  rows = (Uint64)((double)table_rows / pow((double)table_rows, eq_fraction));
12258  if (rows > (table_rows/50)) // EQ-range: Max 2% of rows
12259  rows= (table_rows/50);
12260 
12261  if (min_key_length > eq_bound_offs)
12262  rows/= 2;
12263  if (max_key_length > eq_bound_offs)
12264  rows/= 2;
12265  }
12266  }
12267 
12268  // Make sure that EQ is preferred even if row-count is low
12269  if (eq_bound_len && rows < 2) // At least 2 rows as not exact
12270  rows= 2;
12271  else if (rows < 3)
12272  rows= 3;
12273  DBUG_RETURN(MIN(rows,table_rows));
12274  } while (0);
12275 
12276  DBUG_RETURN(10); /* Poor guess when you don't know anything */
12277 }
12278 
12279 ulonglong ha_ndbcluster::table_flags(void) const
12280 {
12281  THD *thd= current_thd;
12282  ulonglong f=
12283  HA_REC_NOT_IN_SEQ |
12284  HA_NULL_IN_KEY |
12285  HA_AUTO_PART_KEY |
12286  HA_NO_PREFIX_CHAR_KEYS |
12287 #ifndef NDB_WITH_NEW_MRR_INTERFACE
12288  HA_NEED_READ_RANGE_BUFFER |
12289 #endif
12290  HA_CAN_GEOMETRY |
12291  HA_CAN_BIT_FIELD |
12292  HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
12293  HA_PRIMARY_KEY_REQUIRED_FOR_DELETE |
12294  HA_PARTIAL_COLUMN_READ |
12295  HA_HAS_OWN_BINLOGGING |
12296  HA_BINLOG_ROW_CAPABLE |
12297  HA_HAS_RECORDS |
12298 #ifndef NDB_WITHOUT_ONLINE_ALTER
12299  HA_ONLINE_ALTER |
12300 #endif
12301  0;
12302 
12303  /*
12304  To allow for logging of ndb tables during stmt based logging;
12305  flag cabablity, but also turn off flag for OWN_BINLOGGING
12306  */
12307  if (thd->variables.binlog_format == BINLOG_FORMAT_STMT)
12308  f= (f | HA_BINLOG_STMT_CAPABLE) & ~HA_HAS_OWN_BINLOGGING;
12309 
12314  if (THDVAR(thd, join_pushdown))
12315  f= f | HA_BLOCK_CONST_TABLE;
12316 
12317  return f;
12318 }
12319 
12320 const char * ha_ndbcluster::table_type() const
12321 {
12322  return("NDBCLUSTER");
12323 }
12324 uint ha_ndbcluster::max_supported_record_length() const
12325 {
12326  return NDB_MAX_TUPLE_SIZE;
12327 }
12328 uint ha_ndbcluster::max_supported_keys() const
12329 {
12330  return MAX_KEY;
12331 }
12332 uint ha_ndbcluster::max_supported_key_parts() const
12333 {
12334  return NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
12335 }
12336 uint ha_ndbcluster::max_supported_key_length() const
12337 {
12338  return NDB_MAX_KEY_SIZE;
12339 }
12340 uint ha_ndbcluster::max_supported_key_part_length() const
12341 {
12342  return NDB_MAX_KEY_SIZE;
12343 }
12344 bool ha_ndbcluster::low_byte_first() const
12345 {
12346 #ifdef WORDS_BIGENDIAN
12347  return FALSE;
12348 #else
12349  return TRUE;
12350 #endif
12351 }
12352 const char* ha_ndbcluster::index_type(uint key_number)
12353 {
12354  switch (get_index_type(key_number)) {
12355  case ORDERED_INDEX:
12356  case UNIQUE_ORDERED_INDEX:
12357  case PRIMARY_KEY_ORDERED_INDEX:
12358  return "BTREE";
12359  case UNIQUE_INDEX:
12360  case PRIMARY_KEY_INDEX:
12361  default:
12362  return "HASH";
12363  }
12364 }
12365 
12367 {
12368  DBUG_ENTER("ha_ndbcluster::table_cache_type=HA_CACHE_TBL_ASKTRANSACT");
12369  DBUG_RETURN(HA_CACHE_TBL_ASKTRANSACT);
12370 }
12371 
12383 uint ndb_get_commitcount(THD *thd, char *norm_name,
12384  Uint64 *commit_count)
12385 {
12386  char dbname[NAME_LEN + 1];
12387  NDB_SHARE *share;
12388  DBUG_ENTER("ndb_get_commitcount");
12389 
12390  DBUG_PRINT("enter", ("name: %s", norm_name));
12391  pthread_mutex_lock(&ndbcluster_mutex);
12392  if (!(share=(NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
12393  (const uchar*) norm_name,
12394  strlen(norm_name))))
12395  {
12396  pthread_mutex_unlock(&ndbcluster_mutex);
12397  DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables",
12398  norm_name));
12399  DBUG_RETURN(1);
12400  }
12401  /* ndb_share reference temporary, free below */
12402  share->use_count++;
12403  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
12404  share->key, share->use_count));
12405  pthread_mutex_unlock(&ndbcluster_mutex);
12406 
12407  pthread_mutex_lock(&share->mutex);
12408  if (opt_ndb_cache_check_time > 0)
12409  {
12410  if (share->commit_count != 0)
12411  {
12412  *commit_count= share->commit_count;
12413 #ifndef DBUG_OFF
12414  char buff[22];
12415 #endif
12416  DBUG_PRINT("info", ("Getting commit_count: %s from share",
12417  llstr(share->commit_count, buff)));
12418  pthread_mutex_unlock(&share->mutex);
12419  /* ndb_share reference temporary free */
12420  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
12421  share->key, share->use_count));
12422  free_share(&share);
12423  DBUG_RETURN(0);
12424  }
12425  }
12426  DBUG_PRINT("info", ("Get commit_count from NDB"));
12427  Ndb *ndb;
12428  if (!(ndb= check_ndb_in_thd(thd)))
12429  DBUG_RETURN(1);
12430 
12431  ha_ndbcluster::set_dbname(norm_name, dbname);
12432  if (ndb->setDatabaseName(dbname))
12433  {
12434  ERR_RETURN(ndb->getNdbError());
12435  }
12436  uint lock= share->commit_count_lock;
12437  pthread_mutex_unlock(&share->mutex);
12438 
12439  struct Ndb_statistics stat;
12440  {
12441  char tblname[NAME_LEN + 1];
12442  ha_ndbcluster::set_tabname(norm_name, tblname);
12443  Ndb_table_guard ndbtab_g(ndb->getDictionary(), tblname);
12444  if (ndbtab_g.get_table() == 0
12445  || ndb_get_table_statistics(thd, NULL,
12446  FALSE,
12447  ndb,
12448  ndbtab_g.get_table()->getDefaultRecord(),
12449  &stat))
12450  {
12451  /* ndb_share reference temporary free */
12452  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
12453  share->key, share->use_count));
12454  free_share(&share);
12455  DBUG_RETURN(1);
12456  }
12457  }
12458 
12459  pthread_mutex_lock(&share->mutex);
12460  if (share->commit_count_lock == lock)
12461  {
12462 #ifndef DBUG_OFF
12463  char buff[22];
12464 #endif
12465  DBUG_PRINT("info", ("Setting commit_count to %s",
12466  llstr(stat.commit_count, buff)));
12467  share->commit_count= stat.commit_count;
12468  *commit_count= stat.commit_count;
12469  }
12470  else
12471  {
12472  DBUG_PRINT("info", ("Discarding commit_count, comit_count_lock changed"));
12473  *commit_count= 0;
12474  }
12475  pthread_mutex_unlock(&share->mutex);
12476  /* ndb_share reference temporary free */
12477  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
12478  share->key, share->use_count));
12479  free_share(&share);
12480  DBUG_RETURN(0);
12481 }
12482 
12483 
12512 static my_bool
12513 ndbcluster_cache_retrieval_allowed(THD *thd,
12514  char *full_name, uint full_name_len,
12515  ulonglong *engine_data)
12516 {
12517  Uint64 commit_count;
12518  char dbname[NAME_LEN + 1];
12519  char tabname[NAME_LEN + 1];
12520 #ifndef DBUG_OFF
12521  char buff[22], buff2[22];
12522 #endif
12523 
12524  ha_ndbcluster::set_dbname(full_name, dbname);
12525  ha_ndbcluster::set_tabname(full_name, tabname);
12526 
12527  DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
12528  DBUG_PRINT("enter", ("dbname: %s, tabname: %s",
12529  dbname, tabname));
12530 
12531  if (thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
12532  {
12533  /* Don't allow qc to be used if table has been previously
12534  modified in transaction */
12535  if (!check_ndb_in_thd(thd))
12536  DBUG_RETURN(FALSE);
12537  Thd_ndb *thd_ndb= get_thd_ndb(thd);
12538  if (!thd_ndb->changed_tables.is_empty())
12539  {
12540  NDB_SHARE* share;
12541  List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
12542  while ((share= it++))
12543  {
12544  if (strcmp(share->table_name, tabname) == 0 &&
12545  strcmp(share->db, dbname) == 0)
12546  {
12547  DBUG_PRINT("exit", ("No, transaction has changed table"));
12548  DBUG_RETURN(FALSE);
12549  }
12550  }
12551  }
12552  }
12553 
12554  if (ndb_get_commitcount(thd, full_name, &commit_count))
12555  {
12556  *engine_data= 0; /* invalidate */
12557  DBUG_PRINT("exit", ("No, could not retrieve commit_count"));
12558  DBUG_RETURN(FALSE);
12559  }
12560  DBUG_PRINT("info", ("*engine_data: %s, commit_count: %s",
12561  llstr(*engine_data, buff), llstr(commit_count, buff2)));
12562  if (commit_count == 0)
12563  {
12564  *engine_data= 0; /* invalidate */
12565  DBUG_PRINT("exit", ("No, local commit has been performed"));
12566  DBUG_RETURN(FALSE);
12567  }
12568  else if (*engine_data != commit_count)
12569  {
12570  *engine_data= commit_count; /* invalidate */
12571  DBUG_PRINT("exit", ("No, commit_count has changed"));
12572  DBUG_RETURN(FALSE);
12573  }
12574 
12575  DBUG_PRINT("exit", ("OK to use cache, engine_data: %s",
12576  llstr(*engine_data, buff)));
12577  DBUG_RETURN(TRUE);
12578 }
12579 
12580 
12602 my_bool
12604  char *full_name, uint full_name_len,
12605  qc_engine_callback *engine_callback,
12606  ulonglong *engine_data)
12607 {
12608  Uint64 commit_count;
12609 #ifndef DBUG_OFF
12610  char buff[22];
12611 #endif
12612  DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
12613  DBUG_PRINT("enter",("dbname: %s, tabname: %s",
12614  m_dbname, m_tabname));
12615 
12616  if (thd_options(thd) & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
12617  {
12618  /* Don't allow qc to be used if table has been previously
12619  modified in transaction */
12620  Thd_ndb *thd_ndb= get_thd_ndb(thd);
12621  if (!thd_ndb->changed_tables.is_empty())
12622  {
12623  DBUG_ASSERT(m_share);
12624  NDB_SHARE* share;
12625  List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
12626  while ((share= it++))
12627  {
12628  if (m_share == share)
12629  {
12630  DBUG_PRINT("exit", ("No, transaction has changed table"));
12631  DBUG_RETURN(FALSE);
12632  }
12633  }
12634  }
12635  }
12636 
12637  if (ndb_get_commitcount(thd, full_name, &commit_count))
12638  {
12639  *engine_data= 0;
12640  DBUG_PRINT("exit", ("Error, could not get commitcount"));
12641  DBUG_RETURN(FALSE);
12642  }
12643  *engine_data= commit_count;
12644  *engine_callback= ndbcluster_cache_retrieval_allowed;
12645  DBUG_PRINT("exit", ("commit_count: %s", llstr(commit_count, buff)));
12646  DBUG_RETURN(commit_count > 0);
12647 }
12648 
12649 
12659 static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
12660  my_bool not_used __attribute__((unused)))
12661 {
12662  *length= share->key_length;
12663  return (uchar*) share->key;
12664 }
12665 
12666 
12667 #ifndef DBUG_OFF
12668 
12669 static void print_share(const char* where, NDB_SHARE* share)
12670 {
12671  fprintf(DBUG_FILE,
12672  "%s %s.%s: use_count: %u, commit_count: %lu\n",
12673  where, share->db, share->table_name, share->use_count,
12674  (ulong) share->commit_count);
12675  fprintf(DBUG_FILE,
12676  " - key: %s, key_length: %d\n",
12677  share->key, share->key_length);
12678 
12679  Ndb_event_data *event_data= 0;
12680  if (share->event_data)
12681  event_data= share->event_data;
12682  else if (share->op)
12683  event_data= (Ndb_event_data *) share->op->getCustomData();
12684  if (event_data)
12685  {
12686  fprintf(DBUG_FILE,
12687  " - event_data->shadow_table: %p %s.%s\n",
12688  event_data->shadow_table, event_data->shadow_table->s->db.str,
12689  event_data->shadow_table->s->table_name.str);
12690  }
12691 }
12692 
12693 
12694 static void print_ndbcluster_open_tables()
12695 {
12696  DBUG_LOCK_FILE;
12697  fprintf(DBUG_FILE, ">ndbcluster_open_tables\n");
12698  for (uint i= 0; i < ndbcluster_open_tables.records; i++)
12699  print_share("",
12700  (NDB_SHARE*)my_hash_element(&ndbcluster_open_tables, i));
12701  fprintf(DBUG_FILE, "<ndbcluster_open_tables\n");
12702  DBUG_UNLOCK_FILE;
12703 }
12704 
12705 #endif
12706 
12707 
12708 #define dbug_print_open_tables() \
12709  DBUG_EXECUTE("info", \
12710  print_ndbcluster_open_tables(););
12711 
12712 #define dbug_print_share(t, s) \
12713  DBUG_LOCK_FILE; \
12714  DBUG_EXECUTE("info", \
12715  print_share((t), (s));); \
12716  DBUG_UNLOCK_FILE;
12717 
12718 
12719 /*
12720  For some reason a share is still around, try to salvage the situation
12721  by closing all cached tables. If the share still exists, there is an
12722  error somewhere but only report this to the error log. Keep this
12723  "trailing share" but rename it since there are still references to it
12724  to avoid segmentation faults. There is a risk that the memory for
12725  this trailing share leaks.
12726 
12727  Must be called with previous pthread_mutex_lock(&ndbcluster_mutex)
12728 */
12729 int handle_trailing_share(THD *thd, NDB_SHARE *share)
12730 {
12731  static ulong trailing_share_id= 0;
12732  DBUG_ENTER("handle_trailing_share");
12733 
12734  /* ndb_share reference temporary, free below */
12735  ++share->use_count;
12736  if (opt_ndb_extra_logging > 9)
12737  sql_print_information ("handle_trailing_share: %s use_count: %u", share->key, share->use_count);
12738  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
12739  share->key, share->use_count));
12740  pthread_mutex_unlock(&ndbcluster_mutex);
12741 
12742  TABLE_LIST table_list;
12743  memset(&table_list, 0, sizeof(table_list));
12744  table_list.db= share->db;
12745  table_list.alias= table_list.table_name= share->table_name;
12746  close_cached_tables(thd, &table_list, TRUE, FALSE, FALSE);
12747 
12748  pthread_mutex_lock(&ndbcluster_mutex);
12749  /* ndb_share reference temporary free */
12750  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
12751  share->key, share->use_count));
12752  if (!--share->use_count)
12753  {
12754  if (opt_ndb_extra_logging > 9)
12755  sql_print_information ("handle_trailing_share: %s use_count: %u", share->key, share->use_count);
12756  if (opt_ndb_extra_logging)
12757  sql_print_information("NDB_SHARE: trailing share "
12758  "%s(connect_count: %u) "
12759  "released by close_cached_tables at "
12760  "connect_count: %u",
12761  share->key,
12762  share->connect_count,
12763  g_ndb_cluster_connection->get_connect_count());
12764  ndbcluster_real_free_share(&share);
12765  DBUG_RETURN(0);
12766  }
12767  if (opt_ndb_extra_logging > 9)
12768  sql_print_information ("handle_trailing_share: %s use_count: %u", share->key, share->use_count);
12769 
12770  /*
12771  share still exists, if share has not been dropped by server
12772  release that share
12773  */
12774  if (share->state != NSS_DROPPED)
12775  {
12776  share->state= NSS_DROPPED;
12777  /* ndb_share reference create free */
12778  DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
12779  share->key, share->use_count));
12780  --share->use_count;
12781  if (opt_ndb_extra_logging > 9)
12782  sql_print_information ("handle_trailing_share: %s use_count: %u", share->key, share->use_count);
12783 
12784  if (share->use_count == 0)
12785  {
12786  if (opt_ndb_extra_logging)
12787  sql_print_information("NDB_SHARE: trailing share "
12788  "%s(connect_count: %u) "
12789  "released after NSS_DROPPED check "
12790  "at connect_count: %u",
12791  share->key,
12792  share->connect_count,
12793  g_ndb_cluster_connection->get_connect_count());
12794  ndbcluster_real_free_share(&share);
12795  DBUG_RETURN(0);
12796  }
12797  }
12798 
12799  DBUG_PRINT("info", ("NDB_SHARE: %s already exists use_count=%d, op=0x%lx.",
12800  share->key, share->use_count, (long) share->op));
12801  /*
12802  Ignore table shares only opened by util thread
12803  */
12804  if (!((share->use_count == 1) && share->util_thread))
12805  {
12806 #ifdef NDB_LOG_TRAILING_SHARE_ERRORS
12807  sql_print_warning("NDB_SHARE: %s already exists use_count=%d."
12808  " Moving away for safety, but possible memleak.",
12809  share->key, share->use_count);
12810 #endif
12811  }
12812  dbug_print_open_tables();
12813 
12814  /*
12815  Ndb share has not been released as it should
12816  */
12817 #ifdef NOT_YET
12818  DBUG_ASSERT(FALSE);
12819 #endif
12820 
12821  /*
12822  This is probably an error. We can however save the situation
12823  at the cost of a possible mem leak, by "renaming" the share
12824  - First remove from hash
12825  */
12826  my_hash_delete(&ndbcluster_open_tables, (uchar*) share);
12827 
12828  /*
12829  now give it a new name, just a running number
12830  if space is not enough allocate some more
12831  */
12832  {
12833  const uint min_key_length= 10;
12834  if (share->key_length < min_key_length)
12835  {
12836  share->key= (char*) alloc_root(&share->mem_root, min_key_length + 1);
12837  share->key_length= min_key_length;
12838  }
12839  share->key_length=
12840  my_snprintf(share->key, min_key_length + 1, "#leak%lu",
12841  trailing_share_id++);
12842  }
12843  /* Keep it for possible the future trailing free */
12844  my_hash_insert(&ndbcluster_open_tables, (uchar*) share);
12845 
12846  DBUG_RETURN(0);
12847 }
12848 
12849 /*
12850  Rename share is used during rename table.
12851 */
12852 int ndbcluster_prepare_rename_share(NDB_SHARE *share, const char *new_key)
12853 {
12854  /*
12855  allocate and set the new key, db etc
12856  enough space for key, db, and table_name
12857  */
12858  uint new_length= (uint) strlen(new_key);
12859  share->new_key= (char*) alloc_root(&share->mem_root, 2 * (new_length + 1));
12860  strmov(share->new_key, new_key);
12861  return 0;
12862 }
12863 
12864 int ndbcluster_undo_rename_share(THD *thd, NDB_SHARE *share)
12865 {
12866  share->new_key= share->old_names;
12867  ndbcluster_rename_share(thd, share);
12868  return 0;
12869 }
12870 
12871 int ndbcluster_rename_share(THD *thd, NDB_SHARE *share)
12872 {
12873  NDB_SHARE *tmp;
12874  pthread_mutex_lock(&ndbcluster_mutex);
12875  uint new_length= (uint) strlen(share->new_key);
12876  DBUG_PRINT("ndbcluster_rename_share", ("old_key: %s old__length: %d",
12877  share->key, share->key_length));
12878  if ((tmp= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
12879  (const uchar*) share->new_key,
12880  new_length)))
12881  handle_trailing_share(thd, tmp);
12882 
12883  /* remove the share from hash */
12884  my_hash_delete(&ndbcluster_open_tables, (uchar*) share);
12885  dbug_print_open_tables();
12886 
12887  /* save old stuff if insert should fail */
12888  uint old_length= share->key_length;
12889  char *old_key= share->key;
12890 
12891  share->key= share->new_key;
12892  share->key_length= new_length;
12893 
12894  if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
12895  {
12896  // ToDo free the allocated stuff above?
12897  DBUG_PRINT("error", ("ndbcluster_rename_share: my_hash_insert %s failed",
12898  share->key));
12899  share->key= old_key;
12900  share->key_length= old_length;
12901  if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
12902  {
12903  sql_print_error("ndbcluster_rename_share: failed to recover %s", share->key);
12904  DBUG_PRINT("error", ("ndbcluster_rename_share: my_hash_insert %s failed",
12905  share->key));
12906  }
12907  dbug_print_open_tables();
12908  pthread_mutex_unlock(&ndbcluster_mutex);
12909  return -1;
12910  }
12911  dbug_print_open_tables();
12912 
12913  share->db= share->key + new_length + 1;
12914  ha_ndbcluster::set_dbname(share->new_key, share->db);
12915  share->table_name= share->db + strlen(share->db) + 1;
12916  ha_ndbcluster::set_tabname(share->new_key, share->table_name);
12917 
12918  dbug_print_share("ndbcluster_rename_share:", share);
12919  Ndb_event_data *event_data= 0;
12920  if (share->event_data)
12921  event_data= share->event_data;
12922  else if (share->op)
12923  event_data= (Ndb_event_data *) share->op->getCustomData();
12924  if (event_data && event_data->shadow_table)
12925  {
12926  if (!IS_TMP_PREFIX(share->table_name))
12927  {
12928  event_data->shadow_table->s->db.str= share->db;
12929  event_data->shadow_table->s->db.length= strlen(share->db);
12930  event_data->shadow_table->s->table_name.str= share->table_name;
12931  event_data->shadow_table->s->table_name.length= strlen(share->table_name);
12932  }
12933  else
12934  {
12941  }
12942  }
12943  /* else rename will be handled when the ALTER event comes */
12944  share->old_names= old_key;
12945  // ToDo free old_names after ALTER EVENT
12946 
12947  if (opt_ndb_extra_logging > 9)
12948  sql_print_information ("ndbcluster_rename_share: %s-%s use_count: %u", old_key, share->key, share->use_count);
12949 
12950  pthread_mutex_unlock(&ndbcluster_mutex);
12951  return 0;
12952 }
12953 
12954 /*
12955  Increase refcount on existing share.
12956  Always returns share and cannot fail.
12957 */
12958 NDB_SHARE *ndbcluster_get_share(NDB_SHARE *share)
12959 {
12960  pthread_mutex_lock(&ndbcluster_mutex);
12961  share->use_count++;
12962 
12963  dbug_print_open_tables();
12964  dbug_print_share("ndbcluster_get_share:", share);
12965  if (opt_ndb_extra_logging > 9)
12966  sql_print_information ("ndbcluster_get_share: %s use_count: %u", share->key, share->use_count);
12967  pthread_mutex_unlock(&ndbcluster_mutex);
12968  return share;
12969 }
12970 
12971 
12972 /*
12973  Get a share object for key
12974 
12975  Returns share for key, and increases the refcount on the share.
12976 
12977  create_if_not_exists == TRUE:
12978  creates share if it does not alreade exist
12979  returns 0 only due to out of memory, and then sets my_error
12980 
12981  create_if_not_exists == FALSE:
12982  returns 0 if share does not exist
12983 
12984  have_lock == TRUE, pthread_mutex_lock(&ndbcluster_mutex) already taken
12985 */
12986 
12987 NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
12988  bool create_if_not_exists,
12989  bool have_lock)
12990 {
12991  NDB_SHARE *share;
12992  uint length= (uint) strlen(key);
12993  DBUG_ENTER("ndbcluster_get_share");
12994  DBUG_PRINT("enter", ("key: '%s'", key));
12995 
12996  if (!have_lock)
12997  pthread_mutex_lock(&ndbcluster_mutex);
12998  if (!(share= (NDB_SHARE*) my_hash_search(&ndbcluster_open_tables,
12999  (const uchar*) key,
13000  length)))
13001  {
13002  if (!create_if_not_exists)
13003  {
13004  DBUG_PRINT("error", ("get_share: %s does not exist", key));
13005  if (!have_lock)
13006  pthread_mutex_unlock(&ndbcluster_mutex);
13007  DBUG_RETURN(0);
13008  }
13009  if ((share= (NDB_SHARE*) my_malloc(sizeof(*share),
13010  MYF(MY_WME | MY_ZEROFILL))))
13011  {
13012  MEM_ROOT **root_ptr=
13013  my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
13014  MEM_ROOT *old_root= *root_ptr;
13015  init_sql_alloc(&share->mem_root, 1024, 0);
13016  *root_ptr= &share->mem_root; // remember to reset before return
13017  share->flags= 0;
13018  share->state= NSS_INITIAL;
13019  /* enough space for key, db, and table_name */
13020  share->key= (char*) alloc_root(*root_ptr, 2 * (length + 1));
13021  share->key_length= length;
13022  strmov(share->key, key);
13023  if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
13024  {
13025  free_root(&share->mem_root, MYF(0));
13026  my_free((uchar*) share, 0);
13027  *root_ptr= old_root;
13028  if (!have_lock)
13029  pthread_mutex_unlock(&ndbcluster_mutex);
13030  DBUG_RETURN(0);
13031  }
13032  thr_lock_init(&share->lock);
13033  pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
13034  share->commit_count= 0;
13035  share->commit_count_lock= 0;
13036  share->db= share->key + length + 1;
13037  ha_ndbcluster::set_dbname(key, share->db);
13038  share->table_name= share->db + strlen(share->db) + 1;
13039  ha_ndbcluster::set_tabname(key, share->table_name);
13040  if (ndbcluster_binlog_init_share(current_thd, share, table))
13041  {
13042  DBUG_PRINT("error", ("get_share: %s could not init share", key));
13043  ndbcluster_real_free_share(&share);
13044  *root_ptr= old_root;
13045  if (!have_lock)
13046  pthread_mutex_unlock(&ndbcluster_mutex);
13047  DBUG_RETURN(0);
13048  }
13049  *root_ptr= old_root;
13050  }
13051  else
13052  {
13053  DBUG_PRINT("error", ("get_share: failed to alloc share"));
13054  if (!have_lock)
13055  pthread_mutex_unlock(&ndbcluster_mutex);
13056  my_error(ER_OUTOFMEMORY, MYF(0), static_cast<int>(sizeof(*share)));
13057  DBUG_RETURN(0);
13058  }
13059  }
13060  share->use_count++;
13061  if (opt_ndb_extra_logging > 9)
13062  sql_print_information ("ndbcluster_get_share: %s use_count: %u", share->key, share->use_count);
13063 
13064  dbug_print_open_tables();
13065  dbug_print_share("ndbcluster_get_share:", share);
13066  if (!have_lock)
13067  pthread_mutex_unlock(&ndbcluster_mutex);
13068  DBUG_RETURN(share);
13069 }
13070 
13071 
13072 void ndbcluster_real_free_share(NDB_SHARE **share)
13073 {
13074  DBUG_ENTER("ndbcluster_real_free_share");
13075  dbug_print_share("ndbcluster_real_free_share:", *share);
13076 
13077  if (opt_ndb_extra_logging > 9)
13078  sql_print_information ("ndbcluster_real_free_share: %s use_count: %u", (*share)->key, (*share)->use_count);
13079 
13080  ndb_index_stat_free(*share);
13081 
13082  my_hash_delete(&ndbcluster_open_tables, (uchar*) *share);
13083  thr_lock_delete(&(*share)->lock);
13084  pthread_mutex_destroy(&(*share)->mutex);
13085 
13086 #ifdef HAVE_NDB_BINLOG
13087  if ((*share)->m_cfn_share && (*share)->m_cfn_share->m_ex_tab && g_ndb)
13088  {
13089  NDBDICT *dict= g_ndb->getDictionary();
13090  dict->removeTableGlobal(*(*share)->m_cfn_share->m_ex_tab, 0);
13091  (*share)->m_cfn_share->m_ex_tab= 0;
13092  }
13093 #endif
13094  (*share)->new_op= 0;
13095  if ((*share)->event_data)
13096  {
13097  delete (*share)->event_data;
13098  (*share)->event_data= 0;
13099  }
13100  free_root(&(*share)->mem_root, MYF(0));
13101  my_free((uchar*) *share, MYF(0));
13102  *share= 0;
13103 
13104  dbug_print_open_tables();
13105  DBUG_VOID_RETURN;
13106 }
13107 
13108 
13109 void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
13110 {
13111  if (!have_lock)
13112  pthread_mutex_lock(&ndbcluster_mutex);
13113  if (!--(*share)->use_count)
13114  {
13115  if (opt_ndb_extra_logging > 9)
13116  sql_print_information ("ndbcluster_free_share: %s use_count: %u", (*share)->key, (*share)->use_count);
13117  ndbcluster_real_free_share(share);
13118  }
13119  else
13120  {
13121  if (opt_ndb_extra_logging > 9)
13122  sql_print_information ("ndbcluster_free_share: %s use_count: %u", (*share)->key, (*share)->use_count);
13123  dbug_print_open_tables();
13124  dbug_print_share("ndbcluster_free_share:", *share);
13125  }
13126  if (!have_lock)
13127  pthread_mutex_unlock(&ndbcluster_mutex);
13128 }
13129 
13130 
13131 struct ndb_table_statistics_row {
13132  Uint64 rows;
13133  Uint64 commits;
13134  Uint32 size;
13135  Uint64 fixed_mem;
13136  Uint64 var_mem;
13137 };
13138 
13139 int ha_ndbcluster::update_stats(THD *thd,
13140  bool do_read_stat,
13141  bool have_lock,
13142  uint part_id)
13143 {
13144  struct Ndb_statistics stat;
13145  Thd_ndb *thd_ndb= get_thd_ndb(thd);
13146  DBUG_ENTER("ha_ndbcluster::update_stats");
13147  do
13148  {
13149  if (m_share && !do_read_stat)
13150  {
13151  pthread_mutex_lock(&m_share->mutex);
13152  stat= m_share->stat;
13153  pthread_mutex_unlock(&m_share->mutex);
13154 
13155  DBUG_ASSERT(stat.row_count != ~(ha_rows)0); // should never be invalid
13156 
13157  /* Accept shared cached statistics if row_count is valid. */
13158  if (stat.row_count != ~(ha_rows)0)
13159  break;
13160  }
13161 
13162  /* Request statistics from datanodes */
13163  Ndb *ndb= thd_ndb->ndb;
13164  if (ndb->setDatabaseName(m_dbname))
13165  {
13166  DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
13167  }
13168  if (int err= ndb_get_table_statistics(thd, this, TRUE, ndb,
13169  m_ndb_record, &stat,
13170  have_lock, part_id))
13171  {
13172  DBUG_RETURN(err);
13173  }
13174 
13175  /* Update shared statistics with fresh data */
13176  if (m_share)
13177  {
13178  pthread_mutex_lock(&m_share->mutex);
13179  m_share->stat= stat;
13180  pthread_mutex_unlock(&m_share->mutex);
13181  }
13182  break;
13183  }
13184  while(0);
13185 
13186  int no_uncommitted_rows_count= 0;
13187  if (m_table_info && !thd_ndb->m_error)
13188  {
13189  m_table_info->records= stat.row_count;
13190  m_table_info->last_count= thd_ndb->count;
13191  no_uncommitted_rows_count= m_table_info->no_uncommitted_rows_count;
13192  }
13193  stats.mean_rec_length= stat.row_size;
13194  stats.data_file_length= stat.fragment_memory;
13195  stats.records= stat.row_count + no_uncommitted_rows_count;
13196  stats.max_data_file_length= stat.fragment_extent_space;
13197  stats.delete_length= stat.fragment_extent_free_space;
13198 
13199  DBUG_PRINT("exit", ("stats.records: %d "
13200  "stat->row_count: %d "
13201  "no_uncommitted_rows_count: %d"
13202  "stat->fragment_extent_space: %u "
13203  "stat->fragment_extent_free_space: %u",
13204  (int)stats.records,
13205  (int)stat.row_count,
13206  (int)no_uncommitted_rows_count,
13207  (uint)stat.fragment_extent_space,
13208  (uint)stat.fragment_extent_free_space));
13209  DBUG_RETURN(0);
13210 }
13211 
13218 static
13219 void modify_shared_stats(NDB_SHARE *share,
13220  Ndb_local_table_statistics *local_stat)
13221 {
13222  if (local_stat->no_uncommitted_rows_count)
13223  {
13224  pthread_mutex_lock(&share->mutex);
13225  DBUG_ASSERT(share->stat.row_count != ~(ha_rows)0);// should never be invalid
13226  if (share->stat.row_count != ~(ha_rows)0)
13227  {
13228  DBUG_PRINT("info", ("Update row_count for %s, row_count: %lu, with:%d",
13229  share->table_name, (ulong) share->stat.row_count,
13230  local_stat->no_uncommitted_rows_count));
13231  share->stat.row_count=
13232  ((Int64)share->stat.row_count+local_stat->no_uncommitted_rows_count > 0)
13233  ? share->stat.row_count+local_stat->no_uncommitted_rows_count
13234  : 0;
13235  }
13236  pthread_mutex_unlock(&share->mutex);
13237  local_stat->no_uncommitted_rows_count= 0;
13238  }
13239 }
13240 
13241 /* If part_id contains a legal partition id, ndbstat returns the
13242  partition-statistics pertaining to that partition only.
13243  Otherwise, it returns the table-statistics,
13244  which is an aggregate over all partitions of that table.
13245  */
13246 static
13247 int
13248 ndb_get_table_statistics(THD *thd, ha_ndbcluster* file, bool report_error, Ndb* ndb,
13249  const NdbRecord *record,
13250  struct Ndb_statistics * ndbstat,
13251  bool have_lock,
13252  uint part_id)
13253 {
13254  Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
13255  NdbTransaction* pTrans;
13256  NdbError error;
13257  int retries= 100;
13258  int reterr= 0;
13259  int retry_sleep= 30; /* 30 milliseconds */
13260  const char *dummyRowPtr;
13261  NdbOperation::GetValueSpec extraGets[8];
13262  Uint64 rows, commits, fixed_mem, var_mem, ext_space, free_ext_space;
13263  Uint32 size, fragid;
13264 #ifndef DBUG_OFF
13265  char buff[22], buff2[22], buff3[22], buff4[22], buff5[22], buff6[22];
13266 #endif
13267  DBUG_ENTER("ndb_get_table_statistics");
13268 
13269  DBUG_ASSERT(record != 0);
13270 
13271  /* We use the passed in NdbRecord just to get access to the
13272  table, we mask out any/all columns it may have and add
13273  our reads as extraGets. This is necessary as they are
13274  all pseudo-columns
13275  */
13276  extraGets[0].column= NdbDictionary::Column::ROW_COUNT;
13277  extraGets[0].appStorage= &rows;
13278  extraGets[1].column= NdbDictionary::Column::COMMIT_COUNT;
13279  extraGets[1].appStorage= &commits;
13280  extraGets[2].column= NdbDictionary::Column::ROW_SIZE;
13281  extraGets[2].appStorage= &size;
13282  extraGets[3].column= NdbDictionary::Column::FRAGMENT_FIXED_MEMORY;
13283  extraGets[3].appStorage= &fixed_mem;
13284  extraGets[4].column= NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY;
13285  extraGets[4].appStorage= &var_mem;
13286  extraGets[5].column= NdbDictionary::Column::FRAGMENT_EXTENT_SPACE;
13287  extraGets[5].appStorage= &ext_space;
13288  extraGets[6].column= NdbDictionary::Column::FRAGMENT_FREE_EXTENT_SPACE;
13289  extraGets[6].appStorage= &free_ext_space;
13290  extraGets[7].column= NdbDictionary::Column::FRAGMENT;
13291  extraGets[7].appStorage= &fragid;
13292 
13293  const Uint32 codeWords= 1;
13294  Uint32 codeSpace[ codeWords ];
13295  NdbInterpretedCode code(NULL, // Table is irrelevant
13296  &codeSpace[0],
13297  codeWords);
13298  if ((code.interpret_exit_last_row() != 0) ||
13299  (code.finalise() != 0))
13300  {
13301  reterr= code.getNdbError().code;
13302  DBUG_PRINT("exit", ("failed, reterr: %u, NdbError %u(%s)", reterr,
13303  error.code, error.message));
13304  DBUG_RETURN(reterr);
13305  }
13306 
13307  do
13308  {
13309  Uint32 count= 0;
13310  Uint64 sum_rows= 0;
13311  Uint64 sum_commits= 0;
13312  Uint64 sum_row_size= 0;
13313  Uint64 sum_mem= 0;
13314  Uint64 sum_ext_space= 0;
13315  Uint64 sum_free_ext_space= 0;
13316  NdbScanOperation*pOp;
13317  int check;
13318 
13319  if ((pTrans= ndb->startTransaction()) == NULL)
13320  {
13321  error= ndb->getNdbError();
13322  goto retry;
13323  }
13324 
13326  options.optionsPresent= NdbScanOperation::ScanOptions::SO_BATCH |
13327  NdbScanOperation::ScanOptions::SO_GETVALUE |
13328  NdbScanOperation::ScanOptions::SO_INTERPRETED;
13329  /* Set batch_size=1, as we need only one row per fragment. */
13330  options.batch= 1;
13331  options.extraGetValues= &extraGets[0];
13332  options.numExtraGetValues= sizeof(extraGets)/sizeof(extraGets[0]);
13333  options.interpretedCode= &code;
13334 
13335  if ((pOp= pTrans->scanTable(record, NdbOperation::LM_CommittedRead,
13336  empty_mask,
13337  &options,
13338  sizeof(NdbScanOperation::ScanOptions))) == NULL)
13339  {
13340  error= pTrans->getNdbError();
13341  goto retry;
13342  }
13343  thd_ndb->m_scan_count++;
13344  thd_ndb->m_pruned_scan_count += (pOp->getPruned()? 1 : 0);
13345 
13346  thd_ndb->m_execute_count++;
13347  DBUG_PRINT("info", ("execute_count: %u", thd_ndb->m_execute_count));
13348  if (pTrans->execute(NdbTransaction::NoCommit,
13350  TRUE) == -1)
13351  {
13352  error= pTrans->getNdbError();
13353  goto retry;
13354  }
13355 
13356  while ((check= pOp->nextResult(&dummyRowPtr, TRUE, TRUE)) == 0)
13357  {
13358  DBUG_PRINT("info", ("nextResult rows: %d commits: %d"
13359  "fixed_mem_size %d var_mem_size %d "
13360  "fragmentid %d extent_space %d free_extent_space %d",
13361  (int)rows, (int)commits, (int)fixed_mem,
13362  (int)var_mem, (int)fragid, (int)ext_space,
13363  (int)free_ext_space));
13364 
13365  if ((part_id != ~(uint)0) && fragid != part_id)
13366  {
13367  continue;
13368  }
13369 
13370  sum_rows+= rows;
13371  sum_commits+= commits;
13372  if (sum_row_size < size)
13373  sum_row_size= size;
13374  sum_mem+= fixed_mem + var_mem;
13375  count++;
13376  sum_ext_space += ext_space;
13377  sum_free_ext_space += free_ext_space;
13378 
13379  if ((part_id != ~(uint)0) && fragid == part_id)
13380  {
13381  break;
13382  }
13383  }
13384 
13385  if (check == -1)
13386  {
13387  error= pOp->getNdbError();
13388  goto retry;
13389  }
13390 
13391  pOp->close(TRUE);
13392 
13393  ndb->closeTransaction(pTrans);
13394 
13395  ndbstat->row_count= sum_rows;
13396  ndbstat->commit_count= sum_commits;
13397  ndbstat->row_size= (ulong)sum_row_size;
13398  ndbstat->fragment_memory= sum_mem;
13399  ndbstat->fragment_extent_space= sum_ext_space;
13400  ndbstat->fragment_extent_free_space= sum_free_ext_space;
13401 
13402  DBUG_PRINT("exit", ("records: %s commits: %s "
13403  "row_size: %s mem: %s "
13404  "allocated: %s free: %s "
13405  "count: %u",
13406  llstr(sum_rows, buff),
13407  llstr(sum_commits, buff2),
13408  llstr(sum_row_size, buff3),
13409  llstr(sum_mem, buff4),
13410  llstr(sum_ext_space, buff5),
13411  llstr(sum_free_ext_space, buff6),
13412  count));
13413 
13414  DBUG_RETURN(0);
13415 retry:
13416  if(report_error)
13417  {
13418  if (file && pTrans)
13419  {
13420  reterr= file->ndb_err(pTrans, have_lock);
13421  }
13422  else
13423  {
13424  const NdbError& tmp= error;
13425  ERR_PRINT(tmp);
13426  reterr= ndb_to_mysql_error(&tmp);
13427  }
13428  }
13429  else
13430  reterr= error.code;
13431 
13432  if (pTrans)
13433  {
13434  ndb->closeTransaction(pTrans);
13435  pTrans= NULL;
13436  }
13437  if (error.status == NdbError::TemporaryError &&
13438  retries-- && !thd->killed)
13439  {
13440  do_retry_sleep(retry_sleep);
13441  continue;
13442  }
13443  break;
13444  } while(1);
13445  DBUG_PRINT("exit", ("failed, reterr: %u, NdbError %u(%s)", reterr,
13446  error.code, error.message));
13447  DBUG_RETURN(reterr);
13448 }
13449 
13455 int ha_ndbcluster::write_ndb_file(const char *name)
13456 {
13457  File file;
13458  bool error=1;
13459  char path[FN_REFLEN];
13460 
13461  DBUG_ENTER("write_ndb_file");
13462  DBUG_PRINT("enter", ("name: %s", name));
13463 
13464 #ifndef EMBEDDED_LIBRARY
13465  (void)strxnmov(path, FN_REFLEN-1,
13466  mysql_data_home,"/",name,ha_ndb_ext,NullS);
13467 #else
13468  (void)strxnmov(path, FN_REFLEN-1, name,ha_ndb_ext, NullS);
13469 #endif
13470 
13471  if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
13472  {
13473  // It's an empty file
13474  error=0;
13475  my_close(file,MYF(0));
13476  }
13477  DBUG_RETURN(error);
13478 }
13479 
13480 #ifndef NDB_WITH_NEW_MRR_INTERFACE
13481 bool
13482 ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges,
13483  KEY_MULTI_RANGE *end_range,
13484  HANDLER_BUFFER *buffer)
13485 {
13486  DBUG_ENTER("null_value_index_search");
13487  KEY* key_info= table->key_info + active_index;
13488  KEY_MULTI_RANGE *range= ranges;
13489  ulong reclength= table->s->reclength;
13490  uchar *curr= (uchar*)buffer->buffer;
13491  uchar *end_of_buffer= (uchar*)buffer->buffer_end;
13492 
13493  /* All passed ranges whose results could fit into the
13494  * buffer are examined, although some may later be
13495  * marked for skipping, wasting buffer space.
13496  */
13497  assert(!(range->range_flag & SKIP_RANGE));
13498 
13499  for (; range<end_range && curr+reclength <= end_of_buffer;
13500  range++)
13501  {
13502  const uchar *key= range->start_key.key;
13503  uint key_len= range->start_key.length;
13504  if (check_null_in_key(key_info, key, key_len))
13505  DBUG_RETURN(TRUE);
13506  curr += reclength;
13507  }
13508  DBUG_RETURN(FALSE);
13509 }
13510 #endif
13511 
13512 void ha_ndbcluster::check_read_before_write_removal()
13513 {
13514  DBUG_ENTER("check_read_before_write_removal");
13515 
13516  /* Must have determined that rbwr is possible */
13517  assert(m_read_before_write_removal_possible);
13518  m_read_before_write_removal_used= true;
13519 
13520  /* Can't use on table with hidden primary key */
13521  assert(table_share->primary_key != MAX_KEY);
13522 
13523  /* Index must be unique */
13524  DBUG_PRINT("info", ("using index %d", active_index));
13525  const KEY *key= table->key_info + active_index;
13526  assert((key->flags & HA_NOSAME)); NDB_IGNORE_VALUE(key);
13527 
13528  DBUG_VOID_RETURN;
13529 }
13530 
13531 #ifndef NDB_WITH_NEW_MRR_INTERFACE
13532 /*
13533  This is used to check if an ordered index scan is needed for a range in
13534  a multi range read.
13535  If a scan is not needed, we use a faster primary/unique key operation
13536  instead.
13537 */
13538 static my_bool
13539 read_multi_needs_scan(NDB_INDEX_TYPE cur_index_type, const KEY *key_info,
13540  const KEY_MULTI_RANGE *r)
13541 {
13542  if (cur_index_type == ORDERED_INDEX)
13543  return TRUE;
13544  if (cur_index_type == PRIMARY_KEY_INDEX ||
13545  cur_index_type == UNIQUE_INDEX)
13546  return FALSE;
13547  DBUG_ASSERT(cur_index_type == PRIMARY_KEY_ORDERED_INDEX ||
13548  cur_index_type == UNIQUE_ORDERED_INDEX);
13549  if (r->start_key.length != key_info->key_length ||
13550  r->start_key.flag != HA_READ_KEY_EXACT)
13551  return TRUE; // Not exact match, need scan
13552  if (cur_index_type == UNIQUE_ORDERED_INDEX &&
13553  check_null_in_key(key_info, r->start_key.key,r->start_key.length))
13554  return TRUE; // Can't use for NULL values
13555  return FALSE;
13556 }
13557 
13558 int
13560  KEY_MULTI_RANGE *ranges,
13561  uint range_count,
13562  bool sorted,
13563  HANDLER_BUFFER *buffer)
13564 {
13565  KEY* key_info= table->key_info + active_index;
13566  NDB_INDEX_TYPE cur_index_type= get_index_type(active_index);
13567  ulong reclength= table_share->reclength;
13568  NdbTransaction *trans= m_thd_ndb->trans;
13569  int error;
13570 
13571  DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
13572  DBUG_PRINT("info", ("blob fields=%d read_set=0x%x", table_share->blob_fields, table->read_set->bitmap[0]));
13573 
13578  if (uses_blob_value(table->read_set) ||
13579  (cur_index_type == UNIQUE_INDEX &&
13580  has_null_in_unique_index(active_index) &&
13581  null_value_index_search(ranges, ranges+range_count, buffer))
13582  || (m_pushed_join_operation==PUSHED_ROOT &&
13583  !m_disable_pushed_join &&
13584  !m_pushed_join_member->get_query_def().isScanQuery())
13585  || m_delete_cannot_batch || m_update_cannot_batch)
13586  {
13587  DBUG_PRINT("info", ("read_multi_range not possible, falling back to default handler implementation"));
13588  m_disable_multi_read= TRUE;
13589  DBUG_RETURN(handler::read_multi_range_first(found_range_p,
13590  ranges,
13591  range_count,
13592  sorted,
13593  buffer));
13594  }
13595 
13600  if (unlikely((error= close_scan())))
13601  DBUG_RETURN(error);
13602 
13603  m_disable_multi_read= FALSE;
13604 
13605  /*
13606  * Copy arguments into member variables
13607  */
13608  m_multi_ranges= ranges;
13609  multi_range_curr= ranges;
13610  multi_range_end= ranges+range_count;
13611  multi_range_sorted= sorted;
13612  multi_range_buffer= buffer;
13613 
13614  /*
13615  * read multi range will read ranges as follows (if not ordered)
13616  *
13617  * input read order
13618  * ====== ==========
13619  * pk-op 1 pk-op 1
13620  * pk-op 2 pk-op 2
13621  * range 3 range (3,5) NOTE result rows will be intermixed
13622  * pk-op 4 pk-op 4
13623  * range 5
13624  * pk-op 6 pk-op 6
13625  */
13626 
13627  /*
13628  We first loop over all ranges, converting into primary/unique key
13629  operations if possible, and counting ranges that require an
13630  ordered index scan. If the supplied HANDLER_BUFFER is too small, we
13631  may also need to do only part of the multi read at once.
13632 
13633  Afterwards, we create the ordered index scan cursor (if needed).
13634  */
13635 
13636  DBUG_ASSERT(cur_index_type != UNDEFINED_INDEX);
13637  DBUG_ASSERT(m_multi_cursor==NULL);
13638  DBUG_ASSERT(m_active_query==NULL);
13639 
13640  const NdbOperation* lastOp= trans ? trans->getLastDefinedOperation() : 0;
13641  const NdbOperation::LockMode lm = get_ndb_lock_mode(m_lock.type);
13642  uchar *row_buf= (uchar *)buffer->buffer;
13643  const uchar *end_of_buffer= buffer->buffer_end;
13644  uint num_scan_ranges= 0;
13645  uint i;
13646  bool any_real_read= FALSE;
13647 
13648  if (m_read_before_write_removal_possible)
13649  check_read_before_write_removal();
13650  for (i= 0; i < range_count; i++)
13651  {
13652  KEY_MULTI_RANGE *r= &ranges[i];
13653 
13654  part_id_range part_spec;
13655  if (m_use_partition_pruning)
13656  {
13657  get_partition_set(table, table->record[0], active_index, &r->start_key,
13658  &part_spec);
13659  DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
13660  part_spec.start_part, part_spec.end_part));
13661  /*
13662  If partition pruning has found no partition in set
13663  we can skip this scan
13664  */
13665  if (part_spec.start_part > part_spec.end_part)
13666  {
13667  /*
13668  We can skip this partition since the key won't fit into any
13669  partition
13670  */
13671  r->range_flag|= SKIP_RANGE;
13672  row_buf += reclength;
13673  continue;
13674  }
13675  if (!trans &&
13676  (part_spec.start_part == part_spec.end_part))
13677  if (unlikely(!(trans= start_transaction_part_id(part_spec.start_part,
13678  error))))
13679  DBUG_RETURN(error);
13680  }
13681  r->range_flag&= ~(uint)SKIP_RANGE;
13682 
13683  if ((m_pushed_join_operation==PUSHED_ROOT &&
13684  m_pushed_join_member->get_query_def().isScanQuery()) || // Pushed joins restricted to ordered range scan in mrr
13685  read_multi_needs_scan(cur_index_type, key_info, r))
13686  {
13687  if (!trans)
13688  {
13689  // ToDo see if we can use start_transaction_key here instead
13690  if (!m_use_partition_pruning)
13691  {
13692  get_partition_set(table, table->record[0], active_index, &r->start_key,
13693  &part_spec);
13694  if (part_spec.start_part == part_spec.end_part)
13695  {
13696  if (unlikely(!(trans= start_transaction_part_id(part_spec.start_part,
13697  error))))
13698  DBUG_RETURN(error);
13699  }
13700  else if (unlikely(!(trans= start_transaction(error))))
13701  DBUG_RETURN(error);
13702  }
13703  else if (unlikely(!(trans= start_transaction(error))))
13704  DBUG_RETURN(error);
13705  }
13706 
13707  any_real_read= TRUE;
13708  DBUG_PRINT("info", ("any_real_read= TRUE"));
13709 
13710  /*
13711  If we reach the limit of ranges allowed in a single scan: stop
13712  here, send what we have so far, and continue when done with that.
13713  */
13714  if (i > NdbIndexScanOperation::MaxRangeNo)
13715  {
13716  DBUG_PRINT("info", ("Reached the limit of ranges allowed in a single"
13717  "scan"));
13718  break;
13719  }
13720 
13721 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
13722  /* Create the scan operation for the first scan range. */
13723  if (check_if_pushable(NdbQueryOperationDef::OrderedIndexScan,
13724  active_index,
13725  !m_active_query && sorted))
13726  {
13727  if (!m_active_query)
13728  {
13729  const int error= create_pushed_join();
13730  if (unlikely(error))
13731  DBUG_RETURN(error);
13732 
13733  NdbQuery* const query= m_active_query;
13734  if (sorted &&
13735  query->getQueryOperation((uint)PUSHED_ROOT)->setOrdering(NdbQueryOptions::ScanOrdering_ascending))
13736  ERR_RETURN(query->getNdbError());
13737  }
13738  }
13739  else
13740 #endif
13741  if (!m_multi_cursor)
13742  {
13743  if (m_pushed_join_operation == PUSHED_ROOT)
13744  {
13745  m_thd_ndb->m_pushed_queries_dropped++;
13746  }
13747  /* Do a multi-range index scan for ranges not done by primary/unique key. */
13749  NdbInterpretedCode code(m_table);
13750 
13751  options.optionsPresent=
13752  NdbScanOperation::ScanOptions::SO_SCANFLAGS |
13753  NdbScanOperation::ScanOptions::SO_PARALLEL;
13754 
13755  options.scan_flags=
13756  NdbScanOperation::SF_ReadRangeNo |
13757  NdbScanOperation::SF_MultiRange;
13758 
13759  if (lm == NdbOperation::LM_Read)
13760  options.scan_flags|= NdbScanOperation::SF_KeyInfo;
13761  if (sorted)
13762  options.scan_flags|= NdbScanOperation::SF_OrderByFull;
13763 
13764  options.parallel= DEFAULT_PARALLELISM;
13765 
13767  if (table_share->primary_key == MAX_KEY)
13768  get_hidden_fields_scan(&options, gets);
13769 
13770  if (m_cond && m_cond->generate_scan_filter(&code, &options))
13771  ERR_RETURN(code.getNdbError());
13772 
13773  /* Define scan */
13774  NdbIndexScanOperation *scanOp= trans->scanIndex
13775  (m_index[active_index].ndb_record_key,
13776  m_ndb_record,
13777  lm,
13778  (uchar *)(table->read_set->bitmap),
13779  NULL, /* All bounds specified below */
13780  &options,
13782 
13783  if (!scanOp)
13784  ERR_RETURN(trans->getNdbError());
13785 
13786  m_multi_cursor= scanOp;
13787 
13788  /*
13789  We do not get_blob_values() here, as when using blobs we always
13790  fallback to non-batched multi range read (see if statement at
13791  top of this function).
13792  */
13793 
13794  /* We set m_next_row=0 to say that no row was fetched from the scan yet. */
13795  m_next_row= 0;
13796  }
13797 
13798  Ndb::PartitionSpec ndbPartitionSpec;
13799  const Ndb::PartitionSpec* ndbPartSpecPtr= NULL;
13800 
13801  /* If this table uses user-defined partitioning, use MySQLD provided
13802  * partition info as pruning info
13803  * Otherwise, scan range pruning is performed automatically by
13804  * NDBAPI based on distribution key values.
13805  */
13806  if (m_use_partition_pruning &&
13807  m_user_defined_partitioning &&
13808  (part_spec.start_part == part_spec.end_part))
13809  {
13810  DBUG_PRINT("info", ("Range on user-def-partitioned table can be pruned to part %u",
13811  part_spec.start_part));
13812  ndbPartitionSpec.type= Ndb::PartitionSpec::PS_USER_DEFINED;
13813  ndbPartitionSpec.UserDefined.partitionId= part_spec.start_part;
13814  ndbPartSpecPtr= &ndbPartitionSpec;
13815  }
13816 
13817  /* Include this range in the ordered index scan. */
13819  compute_index_bounds(bound, key_info, &r->start_key, &r->end_key, 0);
13820  bound.range_no= i;
13821 
13822  const NdbRecord *key_rec= m_index[active_index].ndb_record_key;
13823  if (m_active_query)
13824  {
13825  DBUG_PRINT("info", ("setBound:%d, for pushed join", bound.range_no));
13826  if (m_active_query->setBound(key_rec, &bound))
13827  {
13828  ERR_RETURN(trans->getNdbError());
13829  }
13830  }
13831  else
13832  {
13833  if (m_multi_cursor->setBound(key_rec,
13834  bound,
13835  ndbPartSpecPtr, // Only for user-def tables
13836  sizeof(Ndb::PartitionSpec)))
13837  {
13838  ERR_RETURN(trans->getNdbError());
13839  }
13840  }
13841 
13842  r->range_flag&= ~(uint)UNIQUE_RANGE;
13843  num_scan_ranges++;
13844  }
13845  else // if ((...PUSHED_ROOT && m_pushed_join->get_query_def().isScanQuery()) ||...
13846  {
13847  if (m_pushed_join_operation == PUSHED_ROOT)
13848  {
13849  m_thd_ndb->m_pushed_queries_dropped++;
13850  }
13851  if (!trans)
13852  {
13853  DBUG_ASSERT(active_index != MAX_KEY);
13854  if (unlikely(!(trans= start_transaction_key(active_index,
13855  r->start_key.key,
13856  error))))
13857  DBUG_RETURN(error);
13858  }
13859  /*
13860  Convert to primary/unique key operation.
13861 
13862  If there is not enough buffer for reading the row: stop here, send
13863  what we have so far, and continue when done with that.
13864  */
13865  if (row_buf + reclength > end_of_buffer)
13866  break;
13867 
13868  if (m_read_before_write_removal_used)
13869  {
13870  r->range_flag|= READ_KEY_FROM_RANGE;
13871  continue;
13872  }
13873  else
13874  {
13875  any_real_read= TRUE;
13876  DBUG_PRINT("info", ("m_read_before_write_removal_used == FALSE, "
13877  "any_real_read= TRUE"));
13878  }
13879  r->range_flag|= UNIQUE_RANGE;
13880 
13881  Uint32 partitionId;
13882  Uint32* ppartitionId = NULL;
13883 
13884  if (m_user_defined_partitioning &&
13885  (cur_index_type == PRIMARY_KEY_ORDERED_INDEX ||
13886  cur_index_type == PRIMARY_KEY_INDEX))
13887  {
13888  partitionId=part_spec.start_part;
13889  ppartitionId=&partitionId;
13890  }
13891 
13892  DBUG_PRINT("info", ("Generating Pk/Unique key read for range %u", i));
13893 
13894  // 'Pushable codepath' is incomplete and expected not
13895  // to be produced as make_join_pushed() handle
13896  // AT_MULTI_UNIQUE_KEY as non-pushable
13897  if (m_pushed_join_operation==PUSHED_ROOT &&
13898  !m_disable_pushed_join &&
13899  !m_pushed_join_member->get_query_def().isScanQuery())
13900  {
13901  DBUG_ASSERT(false); // Incomplete code, should not be executed
13902  DBUG_ASSERT(lm == NdbOperation::LM_CommittedRead);
13903  const int error= pk_unique_index_read_key_pushed(active_index,
13904  r->start_key.key,
13905  ppartitionId);
13906  if (unlikely(error))
13907  DBUG_RETURN(error);
13908  }
13909  else
13910  {
13911  if (m_pushed_join_operation == PUSHED_ROOT)
13912  {
13913  DBUG_PRINT("info", ("Cannot push join due to incomplete implementation."));
13914  m_thd_ndb->m_pushed_queries_dropped++;
13915  }
13916  const NdbOperation* op;
13917  if (!(op= pk_unique_index_read_key(active_index,
13918  r->start_key.key,
13919  row_buf, lm,
13920  ppartitionId)))
13921  ERR_RETURN(trans->getNdbError());
13922  }
13923  row_buf+= reclength;
13924  }
13925  }
13926  DBUG_ASSERT(i > 0 || i == range_count); // Require progress
13927  m_multi_range_defined_end= ranges + i;
13928 
13929  buffer->end_of_used_area= row_buf;
13930 
13931  if (m_active_query != NULL &&
13932  m_pushed_join_member->get_query_def().isScanQuery())
13933  {
13934  m_thd_ndb->m_scan_count++;
13935  if (sorted)
13936  {
13937  m_thd_ndb->m_sorted_scan_count++;
13938  }
13939 
13940  bool prunable = false;
13941  if (unlikely(m_active_query->isPrunable(prunable) != 0))
13942  ERR_RETURN(m_active_query->getNdbError());
13943  if (prunable)
13944  m_thd_ndb->m_pruned_scan_count++;
13945 
13946  DBUG_PRINT("info", ("Is MRR scan-query pruned to 1 partition? :%u", prunable));
13947  DBUG_ASSERT(!m_multi_cursor);
13948  };
13949  if (m_multi_cursor)
13950  {
13951  DBUG_PRINT("info", ("Is MRR scan pruned to 1 partition? :%u",
13952  m_multi_cursor->getPruned()));
13953  m_thd_ndb->m_scan_count++;
13954  m_thd_ndb->m_pruned_scan_count += (m_multi_cursor->getPruned()? 1 : 0);
13955  if (sorted)
13956  {
13957  m_thd_ndb->m_sorted_scan_count++;
13958  }
13959  };
13960 
13961  if (any_real_read)
13962  {
13963  /* Get pointer to first range key operation (not scans) */
13964  const NdbOperation* rangeOp= lastOp ? lastOp->next() :
13965  trans->getFirstDefinedOperation();
13966 
13967  DBUG_PRINT("info", ("Executing reads"));
13968 
13969  if (execute_no_commit_ie(m_thd_ndb, trans) == 0)
13970  {
13971  m_multi_range_result_ptr= buffer->buffer;
13972 
13973  /* We must check the result of any primary or unique key
13974  * ranges now, as these operations may be invalidated by
13975  * further execute+releaseOperations calls on this transaction by
13976  * different handler objects.
13977  */
13978  KEY_MULTI_RANGE* rangeInfo= multi_range_curr;
13979 
13980  for (;rangeInfo < m_multi_range_defined_end; rangeInfo++)
13981  {
13982  DBUG_PRINT("info", ("range flag is %u", rangeInfo->range_flag));
13983  if (rangeInfo->range_flag & SKIP_RANGE)
13984  continue;
13985 
13986  if ((rangeInfo->range_flag & UNIQUE_RANGE) &&
13987  (!(rangeInfo->range_flag & READ_KEY_FROM_RANGE)))
13988  {
13989  assert(rangeOp != NULL);
13990  if (rangeOp->getNdbError().code == 0)
13991  {
13992  /* Successful read, results are in buffer.
13993  */
13994  rangeInfo->range_flag &= ~(uint)EMPTY_RANGE;
13995 
13996  DBUG_PRINT("info", ("Unique range op has result"));
13997  }
13998  else
13999  {
14000  NdbError err= rangeOp->getNdbError();
14001 
14002  if (err.classification !=
14004  DBUG_RETURN(ndb_err(trans));
14005 
14006  DBUG_PRINT("info", ("Unique range op has no result"));
14007  /* Indicate to read_multi_range_next that this
14008  * result is empty
14009  */
14010  rangeInfo->range_flag |= EMPTY_RANGE;
14011  }
14012 
14013  /* Move to next completed operation */
14014  rangeOp= trans->getNextCompletedOperation(rangeOp);
14015  }
14016 
14017  /* For scan ranges, do nothing here */
14018  }
14019  }
14020  else
14021  ERR_RETURN(trans->getNdbError());
14022  }
14023 
14024  DBUG_RETURN(read_multi_range_next(found_range_p));
14025 }
14026 
14027 int
14028 ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
14029 {
14030  DBUG_ENTER("ha_ndbcluster::read_multi_range_next");
14031  if (m_disable_multi_read)
14032  {
14033  DBUG_RETURN(handler::read_multi_range_next(multi_range_found_p));
14034  }
14035 
14036  const ulong reclength= table_share->reclength;
14037 
14038  while (multi_range_curr < m_multi_range_defined_end)
14039  {
14040  if (multi_range_curr->range_flag & SKIP_RANGE)
14041  {
14042  /* Nothing in this range, move to next one, skipping a buffer
14043  'slot'
14044  */
14045  m_multi_range_result_ptr += reclength;
14046  multi_range_curr++;
14047  }
14048  else if (multi_range_curr->range_flag & READ_KEY_FROM_RANGE)
14049  {
14050  DBUG_PRINT("info", ("using read before write removal optimisation"));
14051  KEY* key_info= table->key_info + active_index;
14052  key_restore(table->record[0], (uchar*)multi_range_curr->start_key.key,
14053  key_info, key_info->key_length);
14054  table->status= 0;
14055  multi_range_curr++;
14056  DBUG_RETURN(0);
14057  }
14058  else if (multi_range_curr->range_flag & UNIQUE_RANGE)
14059  {
14060  /*
14061  Move to next range; we can have at most one record from a unique range.
14062  */
14063  KEY_MULTI_RANGE *old_multi_range_curr= multi_range_curr;
14064  multi_range_curr= old_multi_range_curr + 1;
14065  /*
14066  Clear m_active_cursor; it is used as a flag in update_row() /
14067  delete_row() to know whether the current tuple is from a scan
14068  or pk operation.
14069  */
14070  m_active_cursor= NULL;
14071  const uchar *src_row= m_multi_range_result_ptr;
14072  m_multi_range_result_ptr= src_row + table_share->reclength;
14073 
14074  if (!(old_multi_range_curr->range_flag & EMPTY_RANGE))
14075  {
14076  *multi_range_found_p= old_multi_range_curr;
14077  memcpy(table->record[0], src_row, table_share->reclength);
14078  DBUG_RETURN(0);
14079  }
14080 
14081  /* No row found, so fall through to try the next range. */
14082  }
14083  else
14084  {
14085  /* An index scan range. */
14086  {
14087  int res;
14088  if ((res= read_multi_range_fetch_next()) != 0)
14089  DBUG_RETURN(res);
14090  }
14091  if (!m_next_row)
14092  {
14093  /*
14094  The whole scan is done, and the cursor has been closed.
14095  So nothing more for this range. Move to next.
14096  */
14097  multi_range_curr++;
14098  }
14099  else
14100  {
14101  int current_range_no= m_current_range_no;
14102  int expected_range_no;
14103  /*
14104  For a sorted index scan, we will receive rows in increasing range_no
14105  order, so we can return ranges in order, pausing when range_no
14106  indicate that the currently processed range (multi_range_curr) is
14107  done.
14108 
14109  But for unsorted scan, we may receive a high range_no from one
14110  fragment followed by a low range_no from another fragment. So we
14111  need to process all index scan ranges together.
14112  */
14113  if (!multi_range_sorted ||
14114  (expected_range_no= multi_range_curr - m_multi_ranges)
14115  == current_range_no)
14116  {
14117  *multi_range_found_p= m_multi_ranges + current_range_no;
14118  /* Copy out data from the new row. */
14119  unpack_record(table->record[0], m_next_row);
14120  table->status= 0;
14121  /*
14122  Mark that we have used this row, so we need to fetch a new
14123  one on the next call.
14124  */
14125  m_next_row= 0;
14126  /*
14127  Set m_active_cursor; it is used as a flag in update_row() /
14128  delete_row() to know whether the current tuple is from a scan or
14129  pk operation.
14130  */
14131  m_active_cursor= m_multi_cursor;
14132 
14133  DBUG_RETURN(0);
14134  }
14135  else if (current_range_no > expected_range_no)
14136  {
14137  /* Nothing more in scan for this range. Move to next. */
14138  multi_range_curr++;
14139  }
14140  else
14141  {
14142  /*
14143  Should not happen. Ranges should be returned from NDB API in
14144  the order we requested them.
14145  */
14146  DBUG_ASSERT(0);
14147  multi_range_curr++; // Attempt to carry on
14148  }
14149  }
14150  }
14151  }
14152 
14153  if (multi_range_curr == multi_range_end)
14154  {
14155  DBUG_RETURN(HA_ERR_END_OF_FILE);
14156  }
14157 
14158  /*
14159  Read remaining ranges
14160  */
14161  DBUG_RETURN(read_multi_range_first(multi_range_found_p,
14162  multi_range_curr,
14163  multi_range_end - multi_range_curr,
14164  multi_range_sorted,
14165  multi_range_buffer));
14166 }
14167 
14168 /*
14169  Fetch next row from the ordered index cursor in multi range scan.
14170 
14171  We keep the next row in m_next_row, and the range_no of the
14172  next row in m_current_range_no. This is used in sorted index scan
14173  to correctly interleave rows from primary/unique key operations with
14174  rows from the scan.
14175 */
14176 int
14177 ha_ndbcluster::read_multi_range_fetch_next()
14178 {
14179  DBUG_ENTER("read_multi_range_fetch_next");
14180 
14181  if (m_active_query)
14182  {
14183  DBUG_PRINT("info", ("read_multi_range_fetch_next from pushed join, m_next_row:%p", m_next_row));
14184  if (!m_next_row)
14185  {
14186  int res= fetch_next_pushed();
14187  if (res == NdbQuery::NextResult_gotRow)
14188  {
14189  m_current_range_no= 0;
14190 // m_current_range_no= cursor->get_range_no(); // FIXME SPJ, need rangeNo from index scan
14191  }
14192  else if (res == NdbQuery::NextResult_scanComplete)
14193  {
14194  /* We have fetched the last row from the scan. */
14195  m_active_query->close(FALSE);
14196  m_active_query= 0;
14197  m_next_row= 0;
14198  DBUG_RETURN(0);
14199  }
14200  else
14201  {
14202  /* An error. */
14203  DBUG_RETURN(res);
14204  }
14205  }
14206  }
14207  else if (m_multi_cursor)
14208  {
14209  if (!m_next_row)
14210  {
14211  NdbIndexScanOperation *cursor= (NdbIndexScanOperation *)m_multi_cursor;
14212  int res= fetch_next(cursor);
14213  if (res == 0)
14214  {
14215  m_current_range_no= cursor->get_range_no();
14216  }
14217  else if (res == 1)
14218  {
14219  /* We have fetched the last row from the scan. */
14220  cursor->close(FALSE, TRUE);
14221  m_active_cursor= 0;
14222  m_multi_cursor= 0;
14223  m_next_row= 0;
14224  DBUG_RETURN(0);
14225  }
14226  else
14227  {
14228  /* An error. */
14229  DBUG_RETURN(res);
14230  }
14231  }
14232  }
14233  DBUG_RETURN(0);
14234 }
14235 #endif
14236 
14237 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
14238 
14246 static
14247 int ndbcluster_make_pushed_join(handlerton *hton,
14248  THD* thd,
14250 {
14251  DBUG_ENTER("ndbcluster_make_pushed_join");
14252  (void)ha_ndb_ext; // prevents compiler warning.
14253 
14254  if (THDVAR(thd, join_pushdown))
14255  {
14256  ndb_pushed_builder_ctx pushed_builder(*plan);
14257 
14258  for (uint i= 0; i < plan->get_access_count()-1; i++)
14259  {
14260  const AQP::Table_access* const join_root= plan->get_table_access(i);
14261  const ndb_pushed_join* pushed_join= NULL;
14262 
14263  // Try to build a ndb_pushed_join starting from 'join_root'
14264  int error= pushed_builder.make_pushed_join(join_root, pushed_join);
14265  if (unlikely(error))
14266  {
14267  if (error < 0) // getNdbError() gives us the error code
14268  {
14269  ERR_SET(pushed_builder.getNdbError(),error);
14270  }
14271  join_root->get_table()->file->print_error(error, MYF(0));
14272  DBUG_RETURN(error);
14273  }
14274 
14275  // Assign any produced pushed_join definitions to
14276  // the ha_ndbcluster instance representing its root.
14277  if (pushed_join != NULL)
14278  {
14279  ha_ndbcluster* const handler=
14280  static_cast<ha_ndbcluster*>(join_root->get_table()->file);
14281 
14282  error= handler->assign_pushed_join(pushed_join);
14283  if (unlikely(error))
14284  {
14285  delete pushed_join;
14286  handler->print_error(error, MYF(0));
14287  DBUG_RETURN(error);
14288  }
14289  }
14290  }
14291  }
14292  DBUG_RETURN(0);
14293 }
14294 #endif
14295 
14296 
14303 int
14304 ha_ndbcluster::assign_pushed_join(const ndb_pushed_join* pushed_join)
14305 {
14306  DBUG_ENTER("assign_pushed_join");
14307  m_thd_ndb->m_pushed_queries_defined++;
14308 
14309  for (uint i = 0; i < pushed_join->get_operation_count(); i++)
14310  {
14311  const TABLE* const tab= pushed_join->get_table(i);
14312  DBUG_ASSERT(tab->file->ht == ht);
14313  ha_ndbcluster* child= static_cast<ha_ndbcluster*>(tab->file);
14314  child->m_pushed_join_member= pushed_join;
14315  child->m_pushed_join_operation= i;
14316  }
14317 
14318  DBUG_PRINT("info", ("Assigned pushed join with %d child operations",
14319  pushed_join->get_operation_count()-1));
14320 
14321  DBUG_RETURN(0);
14322 }
14323 
14324 
14332 bool
14333 ha_ndbcluster::maybe_pushable_join(const char*& reason) const
14334 {
14335  reason= "";
14336  if (uses_blob_value(table->read_set))
14337  {
14338  reason= "select list can't contain BLOB columns";
14339  return false;
14340  }
14341  if (m_user_defined_partitioning)
14342  {
14343  reason= "has user defined partioning";
14344  return false;
14345  }
14346 
14347  // Pushed operations may not set locks.
14348  const NdbOperation::LockMode lockMode= get_ndb_lock_mode(m_lock.type);
14349  switch (lockMode)
14350  {
14352  return true;
14353 
14354  case NdbOperation::LM_Read:
14356  reason= "lock modes other than 'read committed' not implemented";
14357  return false;
14358 
14359  default: // Other lock modes not used by handler.
14360  assert(false);
14361  return false;
14362  }
14363 
14364  return true;
14365 }
14366 
14381 #ifndef NDB_WITHOUT_JOIN_PUSHDOWN
14382 bool
14383 ha_ndbcluster::check_if_pushable(int type, //NdbQueryOperationDef::Type,
14384  uint idx,
14385  bool needSorted) const
14386 {
14387  if (m_disable_pushed_join)
14388  {
14389  DBUG_PRINT("info", ("Push disabled (HA_EXTRA_KEYREAD)"));
14390  return false;
14391  }
14392  return m_pushed_join_operation == PUSHED_ROOT
14393  && m_pushed_join_member != NULL
14394  && m_pushed_join_member->match_definition(
14395  type,
14396  (idx<MAX_KEY) ? &m_index[idx] : NULL,
14397  needSorted);
14398 }
14399 
14400 int
14401 ha_ndbcluster::create_pushed_join(const NdbQueryParamValue* keyFieldParams, uint paramCnt)
14402 {
14403  DBUG_ENTER("create_pushed_join");
14404  DBUG_ASSERT(m_pushed_join_member && m_pushed_join_operation == PUSHED_ROOT);
14405 
14406  NdbQuery* const query=
14407  m_pushed_join_member->make_query_instance(m_thd_ndb->trans, keyFieldParams, paramCnt);
14408 
14409  if (unlikely(query==NULL))
14410  ERR_RETURN(m_thd_ndb->trans->getNdbError());
14411 
14412  // Bind to instantiated NdbQueryOperations.
14413  for (uint i= 0; i < m_pushed_join_member->get_operation_count(); i++)
14414  {
14415  const TABLE* const tab= m_pushed_join_member->get_table(i);
14416  ha_ndbcluster* handler= static_cast<ha_ndbcluster*>(tab->file);
14417 
14418  DBUG_ASSERT(handler->m_pushed_join_operation==(int)i);
14419  NdbQueryOperation* const op= query->getQueryOperation(i);
14420  handler->m_pushed_operation= op;
14421 
14422  // Bind to result buffers
14423  const NdbRecord* const resultRec= handler->m_ndb_record;
14424  int res= op->setResultRowRef(
14425  resultRec,
14426  handler->_m_next_row,
14427  (uchar *)(tab->read_set->bitmap));
14428  if (unlikely(res))
14429  ERR_RETURN(query->getNdbError());
14430 
14431  // We clear 'm_next_row' to say that no row was fetched from the query yet.
14432  handler->_m_next_row= 0;
14433  }
14434 
14435  DBUG_ASSERT(m_active_query==NULL);
14436  m_active_query= query;
14437  m_thd_ndb->m_pushed_queries_executed++;
14438 
14439  DBUG_RETURN(0);
14440 }
14441 #endif
14442 
14443 
14448 bool
14449 ha_ndbcluster::check_is_pushed() const
14450 {
14451  if (m_pushed_join_member == NULL)
14452  return false;
14453 
14454  handler *root= m_pushed_join_member->get_table(PUSHED_ROOT)->file;
14455  return (static_cast<ha_ndbcluster*>(root)->m_active_query);
14456 }
14457 
14458 uint
14460 {
14461  if (m_pushed_join_member == NULL)
14462  return 0;
14463  else
14464  return m_pushed_join_member->get_operation_count();
14465 }
14466 
14467 const TABLE*
14469 {
14470  if (m_pushed_join_member == NULL)
14471  return NULL;
14472  else
14473  return m_pushed_join_member->get_table(PUSHED_ROOT);
14474 }
14475 
14476 const TABLE*
14478 {
14479  if (m_pushed_join_operation > PUSHED_ROOT)
14480  {
14481  DBUG_ASSERT(m_pushed_join_member!=NULL);
14482  uint parent_ix= m_pushed_join_member
14483  ->get_query_def().getQueryOperation(m_pushed_join_operation)
14484  ->getParentOperation(0)
14485  ->getQueryOperationIx();
14486  return m_pushed_join_member->get_table(parent_ix);
14487  }
14488  return NULL;
14489 }
14490 
14497 char*
14498 ha_ndbcluster::update_table_comment(
14499  /* out: table comment + additional */
14500  const char* comment)/* in: table comment defined by user */
14501 {
14502  THD *thd= current_thd;
14503  uint length= strlen(comment);
14504  if (length > 64000 - 3)
14505  {
14506  return((char*)comment); /* string too long */
14507  }
14508 
14509  Ndb* ndb;
14510  if (!(ndb= get_ndb(thd)))
14511  {
14512  return((char*)comment);
14513  }
14514 
14515  if (ndb->setDatabaseName(m_dbname))
14516  {
14517  return((char*)comment);
14518  }
14519  const NDBTAB* tab= m_table;
14520  DBUG_ASSERT(tab != NULL);
14521 
14522  char *str;
14523  const char *fmt="%s%snumber_of_replicas: %d";
14524  const unsigned fmt_len_plus_extra= length + strlen(fmt);
14525  if ((str= (char*) my_malloc(fmt_len_plus_extra, MYF(0))) == NULL)
14526  {
14527  sql_print_error("ha_ndbcluster::update_table_comment: "
14528  "my_malloc(%u) failed", (unsigned int)fmt_len_plus_extra);
14529  return (char*)comment;
14530  }
14531 
14532  my_snprintf(str,fmt_len_plus_extra,fmt,comment,
14533  length > 0 ? " ":"",
14534  tab->getReplicaCount());
14535  return str;
14536 }
14537 
14538 
14542 pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
14543 {
14544  THD *thd; /* needs to be first for thread_stack */
14545  struct timespec abstime;
14546  Thd_ndb *thd_ndb= NULL;
14547  uint share_list_size= 0;
14548  NDB_SHARE **share_list= NULL;
14549 
14550  my_thread_init();
14551  DBUG_ENTER("ndb_util_thread");
14552  DBUG_PRINT("enter", ("cache_check_time: %lu", opt_ndb_cache_check_time));
14553 
14554  pthread_mutex_lock(&LOCK_ndb_util_thread);
14555 
14556  thd= new THD; /* note that contructor of THD uses DBUG_ */
14557  if (thd == NULL)
14558  {
14559  my_errno= HA_ERR_OUT_OF_MEM;
14560  DBUG_RETURN(NULL);
14561  }
14562  THD_CHECK_SENTRY(thd);
14563  pthread_detach_this_thread();
14564  ndb_util_thread= pthread_self();
14565 
14566  thd->thread_stack= (char*)&thd; /* remember where our stack is */
14567  if (thd->store_globals())
14568  goto ndb_util_thread_fail;
14569  lex_start(thd);
14570  thd->init_for_queries();
14571  thd_set_command(thd, COM_DAEMON);
14572 #ifndef NDB_THD_HAS_NO_VERSION
14573  thd->version=refresh_version;
14574 #endif
14575  thd->client_capabilities = 0;
14576  thd->security_ctx->skip_grants();
14577  my_net_init(&thd->net, 0);
14578 
14579  CHARSET_INFO *charset_connection;
14580  charset_connection= get_charset_by_csname("utf8",
14581  MY_CS_PRIMARY, MYF(MY_WME));
14582  thd->variables.character_set_client= charset_connection;
14583  thd->variables.character_set_results= charset_connection;
14584  thd->variables.collation_connection= charset_connection;
14585  thd->update_charset();
14586 
14587  /* Signal successful initialization */
14588  ndb_util_thread_running= 1;
14589  pthread_cond_signal(&COND_ndb_util_ready);
14590  pthread_mutex_unlock(&LOCK_ndb_util_thread);
14591 
14592  /*
14593  wait for mysql server to start
14594  */
14595  mysql_mutex_lock(&LOCK_server_started);
14596  while (!mysqld_server_started)
14597  {
14598  set_timespec(abstime, 1);
14599  mysql_cond_timedwait(&COND_server_started, &LOCK_server_started,
14600  &abstime);
14601  if (ndbcluster_terminating)
14602  {
14603  mysql_mutex_unlock(&LOCK_server_started);
14604  pthread_mutex_lock(&LOCK_ndb_util_thread);
14605  goto ndb_util_thread_end;
14606  }
14607  }
14608  mysql_mutex_unlock(&LOCK_server_started);
14609 
14610  /*
14611  Wait for cluster to start
14612  */
14613  pthread_mutex_lock(&LOCK_ndb_util_thread);
14614  while (!g_ndb_status.cluster_node_id && (ndbcluster_hton->slot != ~(uint)0))
14615  {
14616  /* ndb not connected yet */
14617  pthread_cond_wait(&COND_ndb_util_thread, &LOCK_ndb_util_thread);
14618  if (ndbcluster_terminating)
14619  goto ndb_util_thread_end;
14620  }
14621  pthread_mutex_unlock(&LOCK_ndb_util_thread);
14622 
14623  /* Get thd_ndb for this thread */
14624  if (!(thd_ndb= Thd_ndb::seize(thd)))
14625  {
14626  sql_print_error("Could not allocate Thd_ndb object");
14627  pthread_mutex_lock(&LOCK_ndb_util_thread);
14628  goto ndb_util_thread_end;
14629  }
14630  thd_set_thd_ndb(thd, thd_ndb);
14631  thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
14632 
14633  if (opt_ndb_extra_logging && ndb_binlog_running)
14634  sql_print_information("NDB Binlog: Ndb tables initially read only.");
14635 
14636  set_timespec(abstime, 0);
14637  for (;;)
14638  {
14639  pthread_mutex_lock(&LOCK_ndb_util_thread);
14640  if (!ndbcluster_terminating)
14641  pthread_cond_timedwait(&COND_ndb_util_thread,
14642  &LOCK_ndb_util_thread,
14643  &abstime);
14644  if (ndbcluster_terminating) /* Shutting down server */
14645  goto ndb_util_thread_end;
14646  pthread_mutex_unlock(&LOCK_ndb_util_thread);
14647 #ifdef NDB_EXTRA_DEBUG_UTIL_THREAD
14648  DBUG_PRINT("ndb_util_thread", ("Started, cache_check_time: %lu",
14649  opt_ndb_cache_check_time));
14650 #endif
14651 
14652  /*
14653  Check if the Ndb object in thd_ndb is still valid(it will be
14654  invalid if connection to cluster has been lost) and recycle
14655  it if necessary.
14656  */
14657  if (!check_ndb_in_thd(thd, false))
14658  {
14659  set_timespec(abstime, 1);
14660  continue;
14661  }
14662 
14663  /*
14664  Regularly give the ndb_binlog component chance to set it self up
14665  i.e at first start it needs to create the ndb_* system tables
14666  and setup event operations on those. In case of lost connection
14667  to cluster, the ndb_* system tables are hopefully still there
14668  but the event operations need to be recreated.
14669  */
14670  if (!ndb_binlog_setup(thd))
14671  {
14672  /* Failed to setup binlog, try again in 1 second */
14673  set_timespec(abstime, 1);
14674  continue;
14675  }
14676 
14677  if (opt_ndb_cache_check_time == 0)
14678  {
14679  /* Wake up in 1 second to check if value has changed */
14680  set_timespec(abstime, 1);
14681  continue;
14682  }
14683 
14684  /* Lock mutex and fill list with pointers to all open tables */
14685  NDB_SHARE *share;
14686  pthread_mutex_lock(&ndbcluster_mutex);
14687  uint i, open_count, record_count= ndbcluster_open_tables.records;
14688  if (share_list_size < record_count)
14689  {
14690  NDB_SHARE ** new_share_list= new NDB_SHARE * [record_count];
14691  if (!new_share_list)
14692  {
14693  sql_print_warning("ndb util thread: malloc failure, "
14694  "query cache not maintained properly");
14695  pthread_mutex_unlock(&ndbcluster_mutex);
14696  goto next; // At least do not crash
14697  }
14698  delete [] share_list;
14699  share_list_size= record_count;
14700  share_list= new_share_list;
14701  }
14702  for (i= 0, open_count= 0; i < record_count; i++)
14703  {
14704  share= (NDB_SHARE *)my_hash_element(&ndbcluster_open_tables, i);
14705  if ((share->use_count - (int) (share->op != 0) - (int) (share->op != 0))
14706  <= 0)
14707  continue; // injector thread is the only user, skip statistics
14708  /* ndb_share reference temporary, free below */
14709  share->use_count++; /* Make sure the table can't be closed */
14710  share->util_thread= true;
14711  DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
14712  share->key, share->use_count));
14713  DBUG_PRINT("ndb_util_thread",
14714  ("Found open table[%d]: %s, use_count: %d",
14715  i, share->table_name, share->use_count));
14716 
14717  /* Store pointer to table */
14718  share_list[open_count++]= share;
14719  }
14720  pthread_mutex_unlock(&ndbcluster_mutex);
14721 
14722  /* Iterate through the open files list */
14723  for (i= 0; i < open_count; i++)
14724  {
14725  share= share_list[i];
14726  if ((share->use_count - (int) (share->op != 0) - (int) (share->op != 0))
14727  <= 1)
14728  {
14729  /*
14730  Util thread and injector thread is the only user, skip statistics
14731  */
14732  /* ndb_share reference temporary free */
14733  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
14734  share->key, share->use_count));
14735 
14736  pthread_mutex_lock(&ndbcluster_mutex);
14737  share->util_thread= false;
14738  free_share(&share, true);
14739  pthread_mutex_unlock(&ndbcluster_mutex);
14740  continue;
14741  }
14742  DBUG_PRINT("ndb_util_thread",
14743  ("Fetching commit count for: %s", share->key));
14744 
14745  struct Ndb_statistics stat;
14746  uint lock;
14747  pthread_mutex_lock(&share->mutex);
14748  lock= share->commit_count_lock;
14749  pthread_mutex_unlock(&share->mutex);
14750  {
14751  /* Contact NDB to get commit count for table */
14752  Ndb* ndb= thd_ndb->ndb;
14753  if (ndb->setDatabaseName(share->db))
14754  {
14755  goto loop_next;
14756  }
14757  Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name);
14758  if (ndbtab_g.get_table() &&
14759  ndb_get_table_statistics(thd, NULL, FALSE, ndb,
14760  ndbtab_g.get_table()->getDefaultRecord(),
14761  &stat) == 0)
14762  {
14763 #ifndef DBUG_OFF
14764  char buff[22], buff2[22];
14765 #endif
14766  DBUG_PRINT("info",
14767  ("Table: %s commit_count: %s rows: %s",
14768  share->key,
14769  llstr(stat.commit_count, buff),
14770  llstr(stat.row_count, buff2)));
14771  }
14772  else
14773  {
14774  DBUG_PRINT("ndb_util_thread",
14775  ("Error: Could not get commit count for table %s",
14776  share->key));
14777  stat.commit_count= 0;
14778  }
14779  }
14780  loop_next:
14781  pthread_mutex_lock(&share->mutex);
14782  if (share->commit_count_lock == lock)
14783  share->commit_count= stat.commit_count;
14784  pthread_mutex_unlock(&share->mutex);
14785 
14786  /* ndb_share reference temporary free */
14787  DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
14788  share->key, share->use_count));
14789  pthread_mutex_lock(&ndbcluster_mutex);
14790  share->util_thread= false;
14791  free_share(&share, true);
14792  pthread_mutex_unlock(&ndbcluster_mutex);
14793  }
14794 next:
14795  /* Calculate new time to wake up */
14796  set_timespec_nsec(abstime, opt_ndb_cache_check_time * 1000000ULL);
14797  }
14798 
14799  pthread_mutex_lock(&LOCK_ndb_util_thread);
14800 
14801 ndb_util_thread_end:
14802  net_end(&thd->net);
14803 ndb_util_thread_fail:
14804  if (share_list)
14805  delete [] share_list;
14806  if (thd_ndb)
14807  {
14808  Thd_ndb::release(thd_ndb);
14809  thd_set_thd_ndb(thd, NULL);
14810  }
14811  thd->cleanup();
14812  delete thd;
14813 
14814  /* signal termination */
14815  ndb_util_thread_running= 0;
14816  pthread_cond_signal(&COND_ndb_util_ready);
14817  pthread_mutex_unlock(&LOCK_ndb_util_thread);
14818  DBUG_PRINT("exit", ("ndb_util_thread"));
14819 
14820  DBUG_LEAVE; // Must match DBUG_ENTER()
14821  my_thread_end();
14822  pthread_exit(0);
14823  return NULL; // Avoid compiler warnings
14824 }
14825 
14826 /*
14827  Condition pushdown
14828 */
14847 const
14848 Item*
14849 ha_ndbcluster::cond_push(const Item *cond)
14850 {
14851  DBUG_ENTER("ha_ndbcluster::cond_push");
14852 
14853 #if 1
14854  if (cond->used_tables() & ~table->map)
14855  {
14862  DBUG_EXECUTE("where",print_where((Item *)cond, "Rejected cond_push", QT_ORDINARY););
14863  DBUG_RETURN(cond);
14864  }
14865 #else
14866  /*
14867  Make sure that 'cond' does not refer field(s) from other tables
14868  or other instances of this table.
14869  (This was a legacy bug in optimizer)
14870  */
14871  DBUG_ASSERT(!(cond->used_tables() & ~table->map));
14872 #endif
14873  if (!m_cond)
14874  m_cond= new ha_ndbcluster_cond;
14875  if (!m_cond)
14876  {
14877  my_errno= HA_ERR_OUT_OF_MEM;
14878  DBUG_RETURN(cond);
14879  }
14880  DBUG_EXECUTE("where",print_where((Item *)cond, m_tabname, QT_ORDINARY););
14881  DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table));
14882 }
14883 
14887 void
14889 {
14890  if (m_cond)
14891  m_cond->cond_pop();
14892 }
14893 
14894 
14895 /*
14896  Implements the SHOW NDB STATUS command.
14897 */
14898 bool
14899 ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print,
14900  enum ha_stat_type stat_type)
14901 {
14902  char name[16];
14903  char buf[IO_SIZE];
14904  uint buflen;
14905  DBUG_ENTER("ndbcluster_show_status");
14906 
14907  if (stat_type != HA_ENGINE_STATUS)
14908  {
14909  DBUG_RETURN(FALSE);
14910  }
14911 
14912  Ndb* ndb= check_ndb_in_thd(thd);
14913  Thd_ndb *thd_ndb= get_thd_ndb(thd);
14914  struct st_ndb_status ns;
14915  if (ndb)
14916  update_status_variables(thd_ndb, &ns, thd_ndb->connection);
14917  else
14918  update_status_variables(NULL, &ns, g_ndb_cluster_connection);
14919 
14920  buflen=
14921  my_snprintf(buf, sizeof(buf),
14922  "cluster_node_id=%ld, "
14923  "connected_host=%s, "
14924  "connected_port=%ld, "
14925  "number_of_data_nodes=%ld, "
14926  "number_of_ready_data_nodes=%ld, "
14927  "connect_count=%ld",
14928  ns.cluster_node_id,
14929  ns.connected_host,
14930  ns.connected_port,
14931  ns.number_of_data_nodes,
14932  ns.number_of_ready_data_nodes,
14933  ns.connect_count);
14934  if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
14935  STRING_WITH_LEN("connection"), buf, buflen))
14936  DBUG_RETURN(TRUE);
14937 
14938  for (int i= 0; i < MAX_NDB_NODES; i++)
14939  {
14940  if (ns.transaction_hint_count[i] > 0 ||
14941  ns.transaction_no_hint_count[i] > 0)
14942  {
14943  uint namelen= my_snprintf(name, sizeof(name), "node[%d]", i);
14944  buflen= my_snprintf(buf, sizeof(buf),
14945  "transaction_hint=%ld, transaction_no_hint=%ld",
14946  ns.transaction_hint_count[i],
14947  ns.transaction_no_hint_count[i]);
14948  if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
14949  name, namelen, buf, buflen))
14950  DBUG_RETURN(TRUE);
14951  }
14952  }
14953 
14954  if (ndb)
14955  {
14957  tmp.m_name= 0;
14958  while (ndb->get_free_list_usage(&tmp))
14959  {
14960  buflen=
14961  my_snprintf(buf, sizeof(buf),
14962  "created=%u, free=%u, sizeof=%u",
14963  tmp.m_created, tmp.m_free, tmp.m_sizeof);
14964  if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
14965  tmp.m_name, strlen(tmp.m_name), buf, buflen))
14966  DBUG_RETURN(TRUE);
14967  }
14968  }
14969  ndbcluster_show_status_binlog(thd, stat_print, stat_type);
14970 
14971  DBUG_RETURN(FALSE);
14972 }
14973 
14974 
14975 int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *create_info)
14976 {
14977  if (unlikely(g_ndb_cluster_connection->get_no_ready() <= 0))
14978  {
14979 err:
14980  my_error(HA_ERR_NO_CONNECTION, MYF(0));
14981  return -1;
14982  }
14983 
14984  THD* thd = current_thd;
14985  if (thd == 0)
14986  goto err;
14987  Thd_ndb * thd_ndb = get_thd_ndb(thd);
14988  if (thd_ndb == 0)
14989  goto err;
14990 
14991  ha_rows max_rows, min_rows;
14992  if (create_info)
14993  {
14994  max_rows= create_info->max_rows;
14995  min_rows= create_info->min_rows;
14996  }
14997  else
14998  {
14999  max_rows= table_share->max_rows;
15000  min_rows= table_share->min_rows;
15001  }
15002  uint no_fragments= get_no_fragments(max_rows >= min_rows ?
15003  max_rows : min_rows);
15004  uint reported_frags;
15005  adjusted_frag_count(thd_ndb->ndb,
15006  no_fragments,
15007  reported_frags);
15008  return reported_frags;
15009 }
15010 
15011 uint32 ha_ndbcluster::calculate_key_hash_value(Field **field_array)
15012 {
15013  Uint32 hash_value;
15014  struct Ndb::Key_part_ptr key_data[MAX_REF_PARTS];
15015  struct Ndb::Key_part_ptr *key_data_ptr= &key_data[0];
15016  Uint32 i= 0;
15017  int ret_val;
15018  Uint64 tmp[(MAX_KEY_SIZE_IN_WORDS*MAX_XFRM_MULTIPLY) >> 1];
15019  void *buf= (void*)&tmp[0];
15020  Ndb *ndb= m_thd_ndb->ndb;
15021  DBUG_ENTER("ha_ndbcluster::calculate_key_hash_value");
15022 
15023  do
15024  {
15025  Field *field= *field_array;
15026  uint len= field->data_length();
15027  DBUG_ASSERT(!field->is_real_null());
15028  if (field->real_type() == MYSQL_TYPE_VARCHAR)
15029  len+= ((Field_varstring*)field)->length_bytes;
15030  key_data[i].ptr= field->ptr;
15031  key_data[i++].len= len;
15032  } while (*(++field_array));
15033  key_data[i].ptr= 0;
15034  if ((ret_val= ndb->computeHash(&hash_value, m_table,
15035  key_data_ptr, buf, sizeof(tmp))))
15036  {
15037  DBUG_PRINT("info", ("ret_val = %d", ret_val));
15038  DBUG_ASSERT(FALSE);
15039  abort();
15040  }
15041  DBUG_RETURN(hash_value);
15042 }
15043 
15044 
15045 /*
15046  Set-up auto-partitioning for NDB Cluster
15047 
15048  SYNOPSIS
15049  set_auto_partitions()
15050  part_info Partition info struct to set-up
15051 
15052  RETURN VALUE
15053  NONE
15054 
15055  DESCRIPTION
15056  Set-up auto partitioning scheme for tables that didn't define any
15057  partitioning. We'll use PARTITION BY KEY() in this case which
15058  translates into partition by primary key if a primary key exists
15059  and partition by hidden key otherwise.
15060 */
15061 
15062 enum ndb_distribution_enum {
15063  NDB_DISTRIBUTION_KEYHASH= 0,
15064  NDB_DISTRIBUTION_LINHASH= 1
15065 };
15066 static const char* distribution_names[]= { "KEYHASH", "LINHASH", NullS };
15067 static ulong opt_ndb_distribution;
15068 static TYPELIB distribution_typelib= {
15069  array_elements(distribution_names) - 1,
15070  "",
15071  distribution_names,
15072  NULL
15073 };
15074 static MYSQL_SYSVAR_ENUM(
15075  distribution, /* name */
15076  opt_ndb_distribution, /* var */
15077  PLUGIN_VAR_RQCMDARG,
15078  "Default distribution for new tables in ndb",
15079  NULL, /* check func. */
15080  NULL, /* update func. */
15081  NDB_DISTRIBUTION_KEYHASH, /* default */
15082  &distribution_typelib /* typelib */
15083 );
15084 
15085 
15086 void ha_ndbcluster::set_auto_partitions(partition_info *part_info)
15087 {
15088  DBUG_ENTER("ha_ndbcluster::set_auto_partitions");
15089  part_info->list_of_part_fields= TRUE;
15090  part_info->part_type= HASH_PARTITION;
15091  switch (opt_ndb_distribution)
15092  {
15093  case NDB_DISTRIBUTION_KEYHASH:
15094  part_info->linear_hash_ind= FALSE;
15095  break;
15096  case NDB_DISTRIBUTION_LINHASH:
15097  part_info->linear_hash_ind= TRUE;
15098  break;
15099  default:
15100  DBUG_ASSERT(false);
15101  break;
15102  }
15103  DBUG_VOID_RETURN;
15104 }
15105 
15106 
15107 int
15108 ha_ndbcluster::set_range_data(const partition_info *part_info,
15109  NdbDictionary::Table& ndbtab) const
15110 {
15111  const uint num_parts = partition_info_num_parts(part_info);
15112  int error= 0;
15113  bool unsigned_flag= part_info->part_expr->unsigned_flag;
15114  DBUG_ENTER("set_range_data");
15115 
15116  int32 *range_data= (int32*)my_malloc(num_parts*sizeof(int32), MYF(0));
15117  if (!range_data)
15118  {
15119  mem_alloc_error(num_parts*sizeof(int32));
15120  DBUG_RETURN(1);
15121  }
15122  for (uint i= 0; i < num_parts; i++)
15123  {
15124  longlong range_val= part_info->range_int_array[i];
15125  if (unsigned_flag)
15126  range_val-= 0x8000000000000000ULL;
15127  if (range_val < INT_MIN32 || range_val >= INT_MAX32)
15128  {
15129  if ((i != num_parts - 1) ||
15130  (range_val != LONGLONG_MAX))
15131  {
15132  my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB");
15133  error= 1;
15134  goto error;
15135  }
15136  range_val= INT_MAX32;
15137  }
15138  range_data[i]= (int32)range_val;
15139  }
15140  ndbtab.setRangeListData(range_data, num_parts);
15141 error:
15142  my_free((char*)range_data, MYF(0));
15143  DBUG_RETURN(error);
15144 }
15145 
15146 
15147 int
15148 ha_ndbcluster::set_list_data(const partition_info *part_info,
15149  NdbDictionary::Table& ndbtab) const
15150 {
15151  const uint num_list_values = partition_info_num_list_values(part_info);
15152  int32 *list_data= (int32*)my_malloc(num_list_values*2*sizeof(int32), MYF(0));
15153  int error= 0;
15154  bool unsigned_flag= part_info->part_expr->unsigned_flag;
15155  DBUG_ENTER("set_list_data");
15156 
15157  if (!list_data)
15158  {
15159  mem_alloc_error(num_list_values*2*sizeof(int32));
15160  DBUG_RETURN(1);
15161  }
15162  for (uint i= 0; i < num_list_values; i++)
15163  {
15164  LIST_PART_ENTRY *list_entry= &part_info->list_array[i];
15165  longlong list_val= list_entry->list_value;
15166  if (unsigned_flag)
15167  list_val-= 0x8000000000000000ULL;
15168  if (list_val < INT_MIN32 || list_val > INT_MAX32)
15169  {
15170  my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB");
15171  error= 1;
15172  goto error;
15173  }
15174  list_data[2*i]= (int32)list_val;
15175  list_data[2*i+1]= list_entry->partition_id;
15176  }
15177  ndbtab.setRangeListData(list_data, 2*num_list_values);
15178 error:
15179  my_free((char*)list_data, MYF(0));
15180  DBUG_RETURN(error);
15181 }
15182 
15183 /*
15184  User defined partitioning set-up. We need to check how many fragments the
15185  user wants defined and which node groups to put those into. Later we also
15186  want to attach those partitions to a tablespace.
15187 
15188  All the functionality of the partition function, partition limits and so
15189  forth are entirely handled by the MySQL Server. There is one exception to
15190  this rule for PARTITION BY KEY where NDB handles the hash function and
15191  this type can thus be handled transparently also by NDB API program.
15192  For RANGE, HASH and LIST and subpartitioning the NDB API programs must
15193  implement the function to map to a partition.
15194 */
15195 
15196 int
15197 ha_ndbcluster::set_up_partition_info(partition_info *part_info,
15198  NdbDictionary::Table& ndbtab) const
15199 {
15200  uint32 frag_data[MAX_PARTITIONS];
15201  char *ts_names[MAX_PARTITIONS];
15202  ulong fd_index= 0, i, j;
15203  NDBTAB::FragmentType ftype= NDBTAB::UserDefined;
15204  partition_element *part_elem;
15205  List_iterator<partition_element> part_it(part_info->partitions);
15206  int error;
15207  DBUG_ENTER("ha_ndbcluster::set_up_partition_info");
15208 
15209  if (part_info->part_type == HASH_PARTITION &&
15210  part_info->list_of_part_fields == TRUE)
15211  {
15212  Field **fields= part_info->part_field_array;
15213 
15214  ftype= NDBTAB::HashMapPartition;
15215 
15216  for (i= 0; i < part_info->part_field_list.elements; i++)
15217  {
15218  NDBCOL *col= ndbtab.getColumn(fields[i]->field_index);
15219  DBUG_PRINT("info",("setting dist key on %s", col->getName()));
15220  col->setPartitionKey(TRUE);
15221  }
15222  }
15223  else
15224  {
15225  if (!current_thd->variables.new_mode)
15226  {
15227  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
15228  ER_ILLEGAL_HA_CREATE_OPTION,
15229  ER(ER_ILLEGAL_HA_CREATE_OPTION),
15230  ndbcluster_hton_name,
15231  "LIST, RANGE and HASH partition disabled by default,"
15232  " use --new option to enable");
15233  DBUG_RETURN(HA_ERR_UNSUPPORTED);
15234  }
15235  /*
15236  Create a shadow field for those tables that have user defined
15237  partitioning. This field stores the value of the partition
15238  function such that NDB can handle reorganisations of the data
15239  even when the MySQL Server isn't available to assist with
15240  calculation of the partition function value.
15241  */
15242  NDBCOL col;
15243  DBUG_PRINT("info", ("Generating partition func value field"));
15244  col.setName("$PART_FUNC_VALUE");
15246  col.setLength(1);
15247  col.setNullable(FALSE);
15248  col.setPrimaryKey(FALSE);
15249  col.setAutoIncrement(FALSE);
15250  ndbtab.addColumn(col);
15251  if (part_info->part_type == RANGE_PARTITION)
15252  {
15253  if ((error= set_range_data(part_info, ndbtab)))
15254  {
15255  DBUG_RETURN(error);
15256  }
15257  }
15258  else if (part_info->part_type == LIST_PARTITION)
15259  {
15260  if ((error= set_list_data(part_info, ndbtab)))
15261  {
15262  DBUG_RETURN(error);
15263  }
15264  }
15265  }
15266  ndbtab.setFragmentType(ftype);
15267  i= 0;
15268  do
15269  {
15270  uint ng;
15271  part_elem= part_it++;
15272  if (!part_info->is_sub_partitioned())
15273  {
15274  ng= part_elem->nodegroup_id;
15275  ts_names[fd_index]= part_elem->tablespace_name;
15276  frag_data[fd_index++]= ng;
15277  }
15278  else
15279  {
15280  List_iterator<partition_element> sub_it(part_elem->subpartitions);
15281  j= 0;
15282  do
15283  {
15284  part_elem= sub_it++;
15285  ng= part_elem->nodegroup_id;
15286  ts_names[fd_index]= part_elem->tablespace_name;
15287  frag_data[fd_index++]= ng;
15288  } while (++j < partition_info_num_subparts(part_info));
15289  }
15290  } while (++i < partition_info_num_parts(part_info));
15291 
15292  const bool use_default_num_parts =
15293  partition_info_use_default_num_partitions(part_info);
15294  ndbtab.setDefaultNoPartitionsFlag(use_default_num_parts);
15295  ndbtab.setLinearFlag(part_info->linear_hash_ind);
15296  {
15297  ha_rows max_rows= table_share->max_rows;
15298  ha_rows min_rows= table_share->min_rows;
15299  if (max_rows < min_rows)
15300  max_rows= min_rows;
15301  if (max_rows != (ha_rows)0) /* default setting, don't set fragmentation */
15302  {
15303  ndbtab.setMaxRows(max_rows);
15304  ndbtab.setMinRows(min_rows);
15305  }
15306  }
15307  ndbtab.setFragmentCount(fd_index);
15308  ndbtab.setFragmentData(frag_data, fd_index);
15309  DBUG_RETURN(0);
15310 }
15311 
15312 #ifndef NDB_WITHOUT_ONLINE_ALTER
15313 static
15314 HA_ALTER_FLAGS supported_alter_operations()
15315 {
15316  HA_ALTER_FLAGS alter_flags;
15317  return alter_flags |
15318  HA_ADD_INDEX |
15319  HA_DROP_INDEX |
15320  HA_ADD_UNIQUE_INDEX |
15321  HA_DROP_UNIQUE_INDEX |
15322  HA_ADD_COLUMN |
15323  HA_COLUMN_STORAGE |
15324  HA_COLUMN_FORMAT |
15325  HA_ADD_PARTITION |
15326  HA_ALTER_TABLE_REORG |
15327  HA_CHANGE_AUTOINCREMENT_VALUE;
15328 }
15329 
15330 int ha_ndbcluster::check_if_supported_alter(TABLE *altered_table,
15331  HA_CREATE_INFO *create_info,
15332  Alter_info *alter_info,
15333  HA_ALTER_FLAGS *alter_flags,
15334  uint table_changes)
15335 {
15336  THD *thd= current_thd;
15337  HA_ALTER_FLAGS not_supported= ~(supported_alter_operations());
15338  uint i;
15339  const NDBTAB *tab= (const NDBTAB *) m_table;
15340  HA_ALTER_FLAGS add_column;
15341  HA_ALTER_FLAGS adding;
15342  HA_ALTER_FLAGS dropping;
15343 
15344  DBUG_ENTER("ha_ndbcluster::check_if_supported_alter");
15345  add_column= add_column | HA_ADD_COLUMN;
15346  adding= adding | HA_ADD_INDEX | HA_ADD_UNIQUE_INDEX;
15347  dropping= dropping | HA_DROP_INDEX | HA_DROP_UNIQUE_INDEX;
15348  partition_info *part_info= altered_table->part_info;
15349  const NDBTAB *old_tab= m_table;
15350 
15351  if (THDVAR(thd, use_copying_alter_table))
15352  {
15353  DBUG_PRINT("info", ("On-line alter table disabled"));
15354  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15355  }
15356 #ifndef DBUG_OFF
15357  {
15358  char dbug_string[HA_MAX_ALTER_FLAGS+1];
15359  alter_flags->print(dbug_string);
15360  DBUG_PRINT("info", ("Not supported %s", dbug_string));
15361  }
15362 #endif
15363 
15364  if (alter_flags->is_set(HA_ALTER_TABLE_REORG))
15365  {
15366  /*
15367  sql_partition.cc tries to compute what is going on
15368  and sets flags...that we clear
15369  */
15370  if (part_info->use_default_num_partitions)
15371  {
15372  alter_flags->clear_bit(HA_COALESCE_PARTITION);
15373  alter_flags->clear_bit(HA_ADD_PARTITION);
15374  }
15375  }
15376 
15377  if ((*alter_flags & not_supported).is_set())
15378  {
15379 #ifndef DBUG_OFF
15380  HA_ALTER_FLAGS tmp = *alter_flags;
15381  tmp&= not_supported;
15382  char dbug_string[HA_MAX_ALTER_FLAGS+1];
15383  tmp.print(dbug_string);
15384  DBUG_PRINT("info", ("Detected unsupported change: %s", dbug_string));
15385 #endif
15386  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15387  }
15388 
15389  if (alter_flags->is_set(HA_ADD_COLUMN) ||
15390  alter_flags->is_set(HA_ADD_PARTITION) ||
15391  alter_flags->is_set(HA_ALTER_TABLE_REORG))
15392  {
15393  Ndb *ndb= get_ndb(thd);
15394  NDBDICT *dict= ndb->getDictionary();
15395  ndb->setDatabaseName(m_dbname);
15396  NdbDictionary::Table new_tab= *old_tab;
15397 
15398  if (alter_flags->is_set(HA_ADD_COLUMN))
15399  {
15400  NDBCOL col;
15401 
15402  /*
15403  Check that we are only adding columns
15404  */
15405  /*
15406  HA_COLUMN_STORAGE & HA_COLUMN_FORMAT
15407  are set if they are specified in an later cmd
15408  even if they're no change. This is probably a bug
15409  conclusion: add them to add_column-mask, so that we silently "accept" them
15410  In case of someone trying to change a column, the HA_CHANGE_COLUMN would be set
15411  which we don't support, so we will still return HA_ALTER_NOT_SUPPORTED in those cases
15412  */
15413  add_column.set_bit(HA_COLUMN_STORAGE);
15414  add_column.set_bit(HA_COLUMN_FORMAT);
15415  if ((*alter_flags & ~add_column).is_set())
15416  {
15417  DBUG_PRINT("info", ("Only add column exclusively can be performed on-line"));
15418  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15419  }
15420  /*
15421  Check for extra fields for hidden primary key
15422  or user defined partitioning
15423  */
15424  if (table_share->primary_key == MAX_KEY ||
15425  part_info->part_type != HASH_PARTITION ||
15426  !part_info->list_of_part_fields)
15427  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15428 
15429  /* Find the new fields */
15430  for (uint i= table->s->fields; i < altered_table->s->fields; i++)
15431  {
15432  Field *field= altered_table->field[i];
15433  DBUG_PRINT("info", ("Found new field %s", field->field_name));
15434  DBUG_PRINT("info", ("storage_type %i, column_format %i",
15435  (uint) field->field_storage_type(),
15436  (uint) field->column_format()));
15437  /* Create new field to check if it can be added */
15438  if ((my_errno= create_ndb_column(0, col, field, create_info,
15439  COLUMN_FORMAT_TYPE_DYNAMIC)))
15440  {
15441  DBUG_PRINT("info", ("create_ndb_column returned %u", my_errno));
15442  DBUG_RETURN(my_errno);
15443  }
15444  new_tab.addColumn(col);
15445  }
15446  }
15447 
15448  if (alter_flags->is_set(HA_ALTER_TABLE_REORG))
15449  {
15450  new_tab.setFragmentCount(0);
15451  new_tab.setFragmentData(0, 0);
15452  }
15453  else if (alter_flags->is_set(HA_ADD_PARTITION))
15454  {
15455  DBUG_PRINT("info", ("Adding partition (%u)", part_info->num_parts));
15456  new_tab.setFragmentCount(part_info->num_parts);
15457  }
15458 
15459  NDB_Modifiers table_modifiers(ndb_table_modifiers);
15460  table_modifiers.parse(thd, "NDB_TABLE=", create_info->comment.str,
15461  create_info->comment.length);
15462  const NDB_Modifier* mod_nologging = table_modifiers.get("NOLOGGING");
15463 
15464  if (mod_nologging->m_found)
15465  {
15466  new_tab.setLogging(!mod_nologging->m_val_bool);
15467  }
15468 
15469  if (dict->supportedAlterTable(*old_tab, new_tab))
15470  {
15471  DBUG_PRINT("info", ("Adding column(s) supported on-line"));
15472  }
15473  else
15474  {
15475  DBUG_PRINT("info",("Adding column not supported on-line"));
15476  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15477  }
15478  }
15479 
15480  /*
15481  Check that we are not adding multiple indexes
15482  */
15483  if ((*alter_flags & adding).is_set())
15484  {
15485  if (((altered_table->s->keys - table->s->keys) != 1) ||
15486  (*alter_flags & dropping).is_set())
15487  {
15488  DBUG_PRINT("info",("Only one index can be added on-line"));
15489  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15490  }
15491  }
15492 
15493  /*
15494  Check that we are not dropping multiple indexes
15495  */
15496  if ((*alter_flags & dropping).is_set())
15497  {
15498  if (((table->s->keys - altered_table->s->keys) != 1) ||
15499  (*alter_flags & adding).is_set())
15500  {
15501  DBUG_PRINT("info",("Only one index can be dropped on-line"));
15502  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15503  }
15504  }
15505 
15506  for (i= 0; i < table->s->fields; i++)
15507  {
15508  Field *field= table->field[i];
15509  const NDBCOL *col= tab->getColumn(i);
15510 
15511  NDBCOL new_col;
15512  create_ndb_column(0, new_col, field, create_info);
15513 
15514  bool index_on_column = false;
15521  for (uint j= 0; j<table->s->keys; j++)
15522  {
15523  KEY* key_info= table->key_info + j;
15524  KEY_PART_INFO* key_part= key_info->key_part;
15525  KEY_PART_INFO* end= key_part+key_info->user_defined_key_parts;
15526  for (; key_part != end; key_part++)
15527  {
15528  if (key_part->field->field_index == i)
15529  {
15530  index_on_column= true;
15531  j= table->s->keys; // break outer loop
15532  break;
15533  }
15534  }
15535  }
15536 
15537  if (index_on_column == false && (*alter_flags & adding).is_set())
15538  {
15539  for (uint j= table->s->keys; j<altered_table->s->keys; j++)
15540  {
15541  KEY* key_info= altered_table->key_info + j;
15542  KEY_PART_INFO* key_part= key_info->key_part;
15543  KEY_PART_INFO* end= key_part+key_info->user_defined_key_parts;
15544  for (; key_part != end; key_part++)
15545  {
15546  if (key_part->field->field_index == i)
15547  {
15548  index_on_column= true;
15549  j= altered_table->s->keys; // break outer loop
15550  break;
15551  }
15552  }
15553  }
15554  }
15555 
15563  if (index_on_column)
15564  {
15565  if (field->field_storage_type() == HA_SM_DISK)
15566  {
15567  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15568  }
15569  new_col.setStorageType(NdbDictionary::Column::StorageTypeMemory);
15570  }
15571  else if (field->field_storage_type() == HA_SM_DEFAULT)
15572  {
15577  new_col.setStorageType(col->getStorageType());
15578  }
15579 
15580  if (col->getStorageType() != new_col.getStorageType())
15581  {
15582  DBUG_PRINT("info", ("Column storage media is changed"));
15583  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15584  }
15585 
15586  if (field->flags & FIELD_IS_RENAMED)
15587  {
15588  DBUG_PRINT("info", ("Field has been renamed, copy table"));
15589  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15590  }
15591 
15592  if ((field->flags & FIELD_IN_ADD_INDEX) &&
15593  (col->getStorageType() == NdbDictionary::Column::StorageTypeDisk))
15594  {
15595  DBUG_PRINT("info", ("add/drop index not supported for disk stored column"));
15596  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15597  }
15598  }
15599 
15600  if ((*alter_flags & HA_CHANGE_AUTOINCREMENT_VALUE).is_set())
15601  {
15602  /* Check that only auto_increment value was changed */
15603  HA_ALTER_FLAGS change_auto_flags=
15604  change_auto_flags | HA_CHANGE_AUTOINCREMENT_VALUE;
15605  if ((*alter_flags & ~change_auto_flags).is_set())
15606  {
15607  DBUG_PRINT("info", ("Not only auto_increment value changed"));
15608  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15609  }
15610  }
15611  else
15612  {
15613  /* Check that row format didn't change */
15614  if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
15615  get_row_type() != create_info->row_type)
15616  {
15617  DBUG_PRINT("info", ("Row format changed"));
15618  DBUG_RETURN(HA_ALTER_NOT_SUPPORTED);
15619  }
15620  }
15621 
15622  DBUG_PRINT("info", ("Ndb supports ALTER on-line"));
15623  DBUG_RETURN(HA_ALTER_SUPPORTED_WAIT_LOCK);
15624 }
15625 
15626 int ha_ndbcluster::alter_table_phase1(THD *thd,
15627  TABLE *altered_table,
15628  HA_CREATE_INFO *create_info,
15629  HA_ALTER_INFO *alter_info,
15630  HA_ALTER_FLAGS *alter_flags)
15631 {
15632  int error= 0;
15633  uint i;
15634  Thd_ndb *thd_ndb= get_thd_ndb(thd);
15635  Ndb *ndb= get_ndb(thd);
15636  NDBDICT *dict= ndb->getDictionary();
15637  ndb->setDatabaseName(m_dbname);
15638  NDB_ALTER_DATA *alter_data;
15639  const NDBTAB *old_tab;
15640  NdbDictionary::Table *new_tab;
15641  HA_ALTER_FLAGS adding;
15642  HA_ALTER_FLAGS dropping;
15643 
15644  DBUG_ENTER("alter_table_phase1");
15645  adding= adding | HA_ADD_INDEX | HA_ADD_UNIQUE_INDEX;
15646  dropping= dropping | HA_DROP_INDEX | HA_DROP_UNIQUE_INDEX;
15647 
15648  if (!thd_ndb->has_required_global_schema_lock("ha_ndbcluster::alter_table_phase1"))
15649  DBUG_RETURN(HA_ERR_NO_CONNECTION);
15650 
15651  if (!(alter_data= new NDB_ALTER_DATA(dict, m_table)))
15652  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
15653  old_tab= alter_data->old_table;
15654  new_tab= alter_data->new_table;
15655  alter_info->data= alter_data;
15656 #ifndef DBUG_OFF
15657  {
15658  char dbug_string[HA_MAX_ALTER_FLAGS+1];
15659  alter_flags->print(dbug_string);
15660  DBUG_PRINT("info", ("altered_table %s, alter_flags %s",
15661  altered_table->s->table_name.str,
15662  (char *) dbug_string));
15663  }
15664 #endif
15665 
15666  prepare_for_alter();
15667 
15668  if (dict->beginSchemaTrans() == -1)
15669  {
15670  DBUG_PRINT("info", ("Failed to start schema transaction"));
15671  ERR_PRINT(dict->getNdbError());
15672  error= ndb_to_mysql_error(&dict->getNdbError());
15673  table->file->print_error(error, MYF(0));
15674  goto err;
15675  }
15676 
15677  if ((*alter_flags & adding).is_set())
15678  {
15679  KEY *key_info;
15680  KEY *key;
15681  uint *idx_p;
15682  uint *idx_end_p;
15683  KEY_PART_INFO *key_part;
15684  KEY_PART_INFO *part_end;
15685  DBUG_PRINT("info", ("Adding indexes"));
15686  key_info= (KEY*) thd->alloc(sizeof(KEY) * alter_info->index_add_count);
15687  key= key_info;
15688  for (idx_p= alter_info->index_add_buffer,
15689  idx_end_p= idx_p + alter_info->index_add_count;
15690  idx_p < idx_end_p;
15691  idx_p++, key++)
15692  {
15693  /* Copy the KEY struct. */
15694  *key= alter_info->key_info_buffer[*idx_p];
15695  /* Fix the key parts. */
15696  part_end= key->key_part + key->user_defined_key_parts;
15697  for (key_part= key->key_part; key_part < part_end; key_part++)
15698  key_part->field= table->field[key_part->fieldnr];
15699  }
15700  if ((error= add_index_impl(thd, altered_table, key_info,
15701  alter_info->index_add_count)))
15702  {
15703  /*
15704  Exchange the key_info for the error message. If we exchange
15705  key number by key name in the message later, we need correct info.
15706  */
15707  KEY *save_key_info= table->key_info;
15708  table->key_info= key_info;
15709  table->file->print_error(error, MYF(0));
15710  table->key_info= save_key_info;
15711  goto abort;
15712  }
15713  }
15714 
15715  if ((*alter_flags & dropping).is_set())
15716  {
15717  uint *key_numbers;
15718  uint *keyno_p;
15719  uint *idx_p;
15720  uint *idx_end_p;
15721  DBUG_PRINT("info", ("Renumbering indexes"));
15722  /* The prepare_drop_index() method takes an array of key numbers. */
15723  key_numbers= (uint*) thd->alloc(sizeof(uint) * alter_info->index_drop_count);
15724  keyno_p= key_numbers;
15725  /* Get the number of each key. */
15726  for (idx_p= alter_info->index_drop_buffer,
15727  idx_end_p= idx_p + alter_info->index_drop_count;
15728  idx_p < idx_end_p;
15729  idx_p++, keyno_p++)
15730  *keyno_p= *idx_p;
15731  /*
15732  Tell the handler to prepare for drop indexes.
15733  This re-numbers the indexes to get rid of gaps.
15734  */
15735  if ((error= prepare_drop_index(table, key_numbers,
15736  alter_info->index_drop_count)))
15737  {
15738  table->file->print_error(error, MYF(0));
15739  goto abort;
15740  }
15741  }
15742 
15743  if (alter_flags->is_set(HA_ADD_COLUMN))
15744  {
15745  NDBCOL col;
15746 
15747  /* Find the new fields */
15748  for (i= table->s->fields; i < altered_table->s->fields; i++)
15749  {
15750  Field *field= altered_table->field[i];
15751  DBUG_PRINT("info", ("Found new field %s", field->field_name));
15752  if ((my_errno= create_ndb_column(thd, col, field, create_info,
15753  COLUMN_FORMAT_TYPE_DYNAMIC)))
15754  {
15755  error= my_errno;
15756  goto abort;
15757  }
15758  /*
15759  If the user has not specified the field format
15760  make it dynamic to enable on-line add attribute
15761  */
15762  if (field->column_format() == COLUMN_FORMAT_TYPE_DEFAULT &&
15763  create_info->row_type == ROW_TYPE_DEFAULT &&
15764  col.getDynamic())
15765  {
15766  push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
15767  ER_ILLEGAL_HA_CREATE_OPTION,
15768  "Converted FIXED field to DYNAMIC "
15769  "to enable on-line ADD COLUMN",
15770  field->field_name);
15771  }
15772  new_tab->addColumn(col);
15773  }
15774  }
15775 
15776  if (alter_flags->is_set(HA_ALTER_TABLE_REORG) || alter_flags->is_set(HA_ADD_PARTITION))
15777  {
15778  if (alter_flags->is_set(HA_ALTER_TABLE_REORG))
15779  {
15780  new_tab->setFragmentCount(0);
15781  new_tab->setFragmentData(0, 0);
15782  }
15783  else if (alter_flags->is_set(HA_ADD_PARTITION))
15784  {
15785  partition_info *part_info= altered_table->part_info;
15786  new_tab->setFragmentCount(part_info->num_parts);
15787  }
15788 
15789  int res= dict->prepareHashMap(*old_tab, *new_tab);
15790  if (res == -1)
15791  {
15792  const NdbError err= dict->getNdbError();
15793  my_errno= ndb_to_mysql_error(&err);
15794  goto abort;
15795  }
15796  }
15797 
15798  DBUG_RETURN(0);
15799 abort:
15800  if (dict->endSchemaTrans(NdbDictionary::Dictionary::SchemaTransAbort)
15801  == -1)
15802  {
15803  DBUG_PRINT("info", ("Failed to abort schema transaction"));
15804  ERR_PRINT(dict->getNdbError());
15805  error= ndb_to_mysql_error(&dict->getNdbError());
15806  }
15807 err:
15808  set_ndb_share_state(m_share, NSS_INITIAL);
15809  /* ndb_share reference schema free */
15810  DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
15811  m_share->key, m_share->use_count));
15812  free_share(&m_share); // Decrease ref_count
15813  delete alter_data;
15814  DBUG_RETURN(error);
15815 }
15816 
15817 int ha_ndbcluster::alter_frm(THD *thd, const char *file,
15818  NDB_ALTER_DATA *alter_data)
15819 {
15820  uchar *data= NULL, *pack_data= NULL;
15821  size_t length, pack_length;
15822  int error= 0;
15823 
15824  DBUG_ENTER("alter_frm");
15825 
15826  DBUG_PRINT("enter", ("file: %s", file));
15827 
15828  NDBDICT *dict= alter_data->dictionary;
15829 
15830  // TODO handle this
15831  DBUG_ASSERT(m_table != 0);
15832 
15833  DBUG_ASSERT(get_ndb_share_state(m_share) == NSS_ALTERED);
15834  if (readfrm(file, &data, &length) ||
15835  packfrm(data, length, &pack_data, &pack_length))
15836  {
15837  DBUG_PRINT("info", ("Missing frm for %s", m_tabname));
15838  my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
15839  my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
15840  error= 1;
15841  my_error(ER_FILE_NOT_FOUND, MYF(0), file);
15842  }
15843  else
15844  {
15845  DBUG_PRINT("info", ("Table %s has changed, altering frm in ndb",
15846  m_tabname));
15847  const NDBTAB *old_tab= alter_data->old_table;
15848  NdbDictionary::Table *new_tab= alter_data->new_table;
15849 
15850  new_tab->setFrm(pack_data, (Uint32)pack_length);
15851  if (dict->alterTableGlobal(*old_tab, *new_tab))
15852  {
15853  DBUG_PRINT("info", ("On-line alter of table %s failed", m_tabname));
15854  error= ndb_to_mysql_error(&dict->getNdbError());
15855  my_error(error, MYF(0));
15856  }
15857  my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
15858  my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
15859  }
15860 
15861  /* ndb_share reference schema(?) free */
15862  DBUG_PRINT("NDB_SHARE", ("%s binlog schema(?) free use_count: %u",
15863  m_share->key, m_share->use_count));
15864 
15865  DBUG_RETURN(error);
15866 }
15867 
15868 int ha_ndbcluster::alter_table_phase2(THD *thd,
15869  TABLE *altered_table,
15870  HA_CREATE_INFO *create_info,
15871  HA_ALTER_INFO *alter_info,
15872  HA_ALTER_FLAGS *alter_flags)
15873 
15874 {
15875  int error= 0;
15876  Thd_ndb *thd_ndb= get_thd_ndb(thd);
15877  NDB_ALTER_DATA *alter_data= (NDB_ALTER_DATA *) alter_info->data;
15878  NDBDICT *dict= alter_data->dictionary;
15879  HA_ALTER_FLAGS dropping;
15880 
15881  DBUG_ENTER("alter_table_phase2");
15882  dropping= dropping | HA_DROP_INDEX | HA_DROP_UNIQUE_INDEX;
15883 
15884  if (!thd_ndb->has_required_global_schema_lock("ha_ndbcluster::alter_table_phase2"))
15885  {
15886  error= HA_ERR_NO_CONNECTION;
15887  goto err;
15888  }
15889 
15890  if ((*alter_flags & dropping).is_set())
15891  {
15892  /* Tell the handler to finally drop the indexes. */
15893  if ((error= final_drop_index(table)))
15894  {
15895  print_error(error, MYF(0));
15896  goto abort;
15897  }
15898  }
15899 
15900  DBUG_PRINT("info", ("getting frm file %s", altered_table->s->path.str));
15901 
15902  DBUG_ASSERT(alter_data);
15903  error= alter_frm(thd, altered_table->s->path.str, alter_data);
15904  if (!error)
15905  {
15906  /*
15907  * Alter succesful, commit schema transaction
15908  */
15909  if (dict->endSchemaTrans() == -1)
15910  {
15911  error= ndb_to_mysql_error(&dict->getNdbError());
15912  DBUG_PRINT("info", ("Failed to commit schema transaction, error %u",
15913  error));
15914  table->file->print_error(error, MYF(0));
15915  goto err;
15916  }
15917  if ((*alter_flags & HA_CHANGE_AUTOINCREMENT_VALUE).is_set())
15918  error= set_auto_inc_val(thd, create_info->auto_increment_value);
15919  if (error)
15920  {
15921  DBUG_PRINT("info", ("Failed to set auto_increment value"));
15922  goto err;
15923  }
15924  }
15925  else // if (error)
15926  {
15927 abort:
15928  if (dict->endSchemaTrans(NdbDictionary::Dictionary::SchemaTransAbort)
15929  == -1)
15930  {
15931  DBUG_PRINT("info", ("Failed to abort schema transaction"));
15932  ERR_PRINT(dict->getNdbError());
15933  }
15934 err:
15935  /* ndb_share reference schema free */
15936  DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
15937  m_share->key, m_share->use_count));
15938  delete alter_data;
15939  alter_info->data= 0;
15940  }
15941  set_ndb_share_state(m_share, NSS_INITIAL);
15942  free_share(&m_share); // Decrease ref_count
15943  DBUG_RETURN(error);
15944 }
15945 
15946 int ha_ndbcluster::alter_table_phase3(THD *thd, TABLE *table,
15947  HA_CREATE_INFO *create_info,
15948  HA_ALTER_INFO *alter_info,
15949  HA_ALTER_FLAGS *alter_flags)
15950 {
15951  Thd_ndb *thd_ndb= get_thd_ndb(thd);
15952  DBUG_ENTER("alter_table_phase3");
15953 
15954  NDB_ALTER_DATA *alter_data= (NDB_ALTER_DATA *) alter_info->data;
15955  if (!thd_ndb->has_required_global_schema_lock("ha_ndbcluster::alter_table_phase3"))
15956  {
15957  delete alter_data;
15958  alter_info->data= 0;
15959  DBUG_RETURN(HA_ERR_NO_CONNECTION);
15960  }
15961 
15962  const char *db= table->s->db.str;
15963  const char *name= table->s->table_name.str;
15964 
15965  /*
15966  all mysqld's will read frms from disk and setup new
15967  event operation for the table (new_op)
15968  */
15969  uint32 table_id= 0, table_version= 0;
15970  DBUG_ASSERT(alter_data != 0);
15971  if (alter_data)
15972  {
15973  table_id= alter_data->table_id;
15974  table_version= alter_data->old_table_version;
15975  }
15976  ndbcluster_log_schema_op(thd, thd->query(), thd->query_length(),
15977  db, name,
15978  table_id, table_version,
15979  SOT_ONLINE_ALTER_TABLE_PREPARE,
15980  NULL, NULL);
15981 
15982  /*
15983  Get table id/version for new table
15984  */
15985  table_id= 0;
15986  table_version= 0;
15987  {
15988  Ndb* ndb= get_ndb(thd);
15989  DBUG_ASSERT(ndb != 0);
15990  if (ndb)
15991  {
15992  ndb->setDatabaseName(db);
15993  Ndb_table_guard ndbtab(ndb->getDictionary(), name);
15994  const NDBTAB *new_tab= ndbtab.get_table();
15995  DBUG_ASSERT(new_tab != 0);
15996  if (new_tab)
15997  {
15998  table_id= new_tab->getObjectId();
15999  table_version= new_tab->getObjectVersion();
16000  }
16001  }
16002  }
16003 
16004  /*
16005  all mysqld's will switch to using the new_op, and delete the old
16006  event operation
16007  */
16008  ndbcluster_log_schema_op(thd, thd->query(), thd->query_length(),
16009  db, name,
16010  table_id, table_version,
16011  SOT_ONLINE_ALTER_TABLE_COMMIT,
16012  NULL, NULL);
16013 
16014  delete alter_data;
16015  alter_info->data= 0;
16016  DBUG_RETURN(0);
16017 }
16018 #endif
16019 
16020 bool set_up_tablespace(st_alter_tablespace *alter_info,
16021  NdbDictionary::Tablespace *ndb_ts)
16022 {
16023  if (alter_info->extent_size >= (Uint64(1) << 32))
16024  {
16025  // TODO set correct error
16026  return TRUE;
16027  }
16028  ndb_ts->setName(alter_info->tablespace_name);
16029  ndb_ts->setExtentSize(Uint32(alter_info->extent_size));
16030  ndb_ts->setDefaultLogfileGroup(alter_info->logfile_group_name);
16031  return FALSE;
16032 }
16033 
16034 bool set_up_datafile(st_alter_tablespace *alter_info,
16035  NdbDictionary::Datafile *ndb_df)
16036 {
16037  if (alter_info->max_size > 0)
16038  {
16039  my_error(ER_TABLESPACE_AUTO_EXTEND_ERROR, MYF(0));
16040  return TRUE;
16041  }
16042  ndb_df->setPath(alter_info->data_file_name);
16043  ndb_df->setSize(alter_info->initial_size);
16044  ndb_df->setTablespace(alter_info->tablespace_name);
16045  return FALSE;
16046 }
16047 
16048 bool set_up_logfile_group(st_alter_tablespace *alter_info,
16050 {
16051  if (alter_info->undo_buffer_size >= (Uint64(1) << 32))
16052  {
16053  // TODO set correct error
16054  return TRUE;
16055  }
16056 
16057  ndb_lg->setName(alter_info->logfile_group_name);
16058  ndb_lg->setUndoBufferSize(Uint32(alter_info->undo_buffer_size));
16059  return FALSE;
16060 }
16061 
16062 bool set_up_undofile(st_alter_tablespace *alter_info,
16063  NdbDictionary::Undofile *ndb_uf)
16064 {
16065  ndb_uf->setPath(alter_info->undo_file_name);
16066  ndb_uf->setSize(alter_info->initial_size);
16067  ndb_uf->setLogfileGroup(alter_info->logfile_group_name);
16068  return FALSE;
16069 }
16070 
16071 int ndbcluster_alter_tablespace(handlerton *hton,
16072  THD* thd, st_alter_tablespace *alter_info)
16073 {
16074  int is_tablespace= 0;
16075  NdbError err;
16076  NDBDICT *dict;
16077  int error;
16078  const char *errmsg;
16079  Ndb *ndb;
16080  DBUG_ENTER("ndbcluster_alter_tablespace");
16081  LINT_INIT(errmsg);
16082 
16083  ndb= check_ndb_in_thd(thd);
16084  if (ndb == NULL)
16085  {
16086  DBUG_RETURN(HA_ERR_NO_CONNECTION);
16087  }
16088  dict= ndb->getDictionary();
16089 
16090  uint32 table_id= 0, table_version= 0;
16091  switch (alter_info->ts_cmd_type){
16092  case (CREATE_TABLESPACE):
16093  {
16094  error= ER_CREATE_FILEGROUP_FAILED;
16095 
16097  NdbDictionary::Datafile ndb_df;
16099  if (set_up_tablespace(alter_info, &ndb_ts))
16100  {
16101  DBUG_RETURN(1);
16102  }
16103  if (set_up_datafile(alter_info, &ndb_df))
16104  {
16105  DBUG_RETURN(1);
16106  }
16107  errmsg= "TABLESPACE";
16108  if (dict->createTablespace(ndb_ts, &objid))
16109  {
16110  DBUG_PRINT("error", ("createTablespace returned %d", error));
16111  goto ndberror;
16112  }
16113  table_id = objid.getObjectId();
16114  table_version = objid.getObjectVersion();
16115  if (dict->getWarningFlags() &
16116  NdbDictionary::Dictionary::WarnExtentRoundUp)
16117  {
16118  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16119  dict->getWarningFlags(),
16120  "Extent size rounded up to kernel page size");
16121  }
16122  DBUG_PRINT("alter_info", ("Successfully created Tablespace"));
16123  errmsg= "DATAFILE";
16124  if (dict->createDatafile(ndb_df))
16125  {
16126  err= dict->getNdbError();
16127  NdbDictionary::Tablespace tmp= dict->getTablespace(ndb_ts.getName());
16128  if (dict->getNdbError().code == 0 &&
16129  tmp.getObjectId() == objid.getObjectId() &&
16130  tmp.getObjectVersion() == objid.getObjectVersion())
16131  {
16132  dict->dropTablespace(tmp);
16133  }
16134 
16135  DBUG_PRINT("error", ("createDatafile returned %d", error));
16136  goto ndberror2;
16137  }
16138  if (dict->getWarningFlags() &
16139  NdbDictionary::Dictionary::WarnDatafileRoundUp)
16140  {
16141  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16142  dict->getWarningFlags(),
16143  "Datafile size rounded up to extent size");
16144  }
16145  else /* produce only 1 message */
16146  if (dict->getWarningFlags() &
16147  NdbDictionary::Dictionary::WarnDatafileRoundDown)
16148  {
16149  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16150  dict->getWarningFlags(),
16151  "Datafile size rounded down to extent size");
16152  }
16153  is_tablespace= 1;
16154  break;
16155  }
16156  case (ALTER_TABLESPACE):
16157  {
16158  error= ER_ALTER_FILEGROUP_FAILED;
16159  if (alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE)
16160  {
16161  NdbDictionary::Datafile ndb_df;
16162  if (set_up_datafile(alter_info, &ndb_df))
16163  {
16164  DBUG_RETURN(1);
16165  }
16166  errmsg= " CREATE DATAFILE";
16168  if (dict->createDatafile(ndb_df, false, &objid))
16169  {
16170  goto ndberror;
16171  }
16172  table_id= objid.getObjectId();
16173  table_version= objid.getObjectVersion();
16174  if (dict->getWarningFlags() &
16175  NdbDictionary::Dictionary::WarnDatafileRoundUp)
16176  {
16177  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16178  dict->getWarningFlags(),
16179  "Datafile size rounded up to extent size");
16180  }
16181  else /* produce only 1 message */
16182  if (dict->getWarningFlags() &
16183  NdbDictionary::Dictionary::WarnDatafileRoundDown)
16184  {
16185  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16186  dict->getWarningFlags(),
16187  "Datafile size rounded down to extent size");
16188  }
16189  }
16190  else if(alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE)
16191  {
16192  NdbDictionary::Tablespace ts= dict->getTablespace(alter_info->tablespace_name);
16193  NdbDictionary::Datafile df= dict->getDatafile(0, alter_info->data_file_name);
16195  df.getTablespaceId(&objid);
16196  table_id = df.getObjectId();
16197  table_version = df.getObjectVersion();
16198  if (ts.getObjectId() == objid.getObjectId() &&
16199  strcmp(df.getPath(), alter_info->data_file_name) == 0)
16200  {
16201  errmsg= " DROP DATAFILE";
16202  if (dict->dropDatafile(df))
16203  {
16204  goto ndberror;
16205  }
16206  }
16207  else
16208  {
16209  DBUG_PRINT("error", ("No such datafile"));
16210  my_error(ER_ALTER_FILEGROUP_FAILED, MYF(0), " NO SUCH FILE");
16211  DBUG_RETURN(1);
16212  }
16213  }
16214  else
16215  {
16216  DBUG_PRINT("error", ("Unsupported alter tablespace: %d",
16217  alter_info->ts_alter_tablespace_type));
16218  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
16219  }
16220  is_tablespace= 1;
16221  break;
16222  }
16223  case (CREATE_LOGFILE_GROUP):
16224  {
16225  error= ER_CREATE_FILEGROUP_FAILED;
16227  NdbDictionary::Undofile ndb_uf;
16229  if (alter_info->undo_file_name == NULL)
16230  {
16231  /*
16232  REDO files in LOGFILE GROUP not supported yet
16233  */
16234  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
16235  }
16236  if (set_up_logfile_group(alter_info, &ndb_lg))
16237  {
16238  DBUG_RETURN(1);
16239  }
16240  errmsg= "LOGFILE GROUP";
16241  if (dict->createLogfileGroup(ndb_lg, &objid))
16242  {
16243  goto ndberror;
16244  }
16245  table_id = objid.getObjectId();
16246  table_version = objid.getObjectVersion();
16247  if (dict->getWarningFlags() &
16248  NdbDictionary::Dictionary::WarnUndobufferRoundUp)
16249  {
16250  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16251  dict->getWarningFlags(),
16252  "Undo buffer size rounded up to kernel page size");
16253  }
16254  DBUG_PRINT("alter_info", ("Successfully created Logfile Group"));
16255  if (set_up_undofile(alter_info, &ndb_uf))
16256  {
16257  DBUG_RETURN(1);
16258  }
16259  errmsg= "UNDOFILE";
16260  if (dict->createUndofile(ndb_uf))
16261  {
16262  err= dict->getNdbError();
16263  NdbDictionary::LogfileGroup tmp= dict->getLogfileGroup(ndb_lg.getName());
16264  if (dict->getNdbError().code == 0 &&
16265  tmp.getObjectId() == objid.getObjectId() &&
16266  tmp.getObjectVersion() == objid.getObjectVersion())
16267  {
16268  dict->dropLogfileGroup(tmp);
16269  }
16270  goto ndberror2;
16271  }
16272  if (dict->getWarningFlags() &
16273  NdbDictionary::Dictionary::WarnUndofileRoundDown)
16274  {
16275  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16276  dict->getWarningFlags(),
16277  "Undofile size rounded down to kernel page size");
16278  }
16279  break;
16280  }
16281  case (ALTER_LOGFILE_GROUP):
16282  {
16283  error= ER_ALTER_FILEGROUP_FAILED;
16284  if (alter_info->undo_file_name == NULL)
16285  {
16286  /*
16287  REDO files in LOGFILE GROUP not supported yet
16288  */
16289  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
16290  }
16291  NdbDictionary::Undofile ndb_uf;
16292  if (set_up_undofile(alter_info, &ndb_uf))
16293  {
16294  DBUG_RETURN(1);
16295  }
16296  errmsg= "CREATE UNDOFILE";
16298  if (dict->createUndofile(ndb_uf, false, &objid))
16299  {
16300  goto ndberror;
16301  }
16302  table_id = objid.getObjectId();
16303  table_version = objid.getObjectVersion();
16304  if (dict->getWarningFlags() &
16305  NdbDictionary::Dictionary::WarnUndofileRoundDown)
16306  {
16307  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
16308  dict->getWarningFlags(),
16309  "Undofile size rounded down to kernel page size");
16310  }
16311  break;
16312  }
16313  case (DROP_TABLESPACE):
16314  {
16315  error= ER_DROP_FILEGROUP_FAILED;
16316  errmsg= "TABLESPACE";
16318  dict->getTablespace(alter_info->tablespace_name);
16319  table_id= ts.getObjectId();
16320  table_version= ts.getObjectVersion();
16321  if (dict->dropTablespace(ts))
16322  {
16323  goto ndberror;
16324  }
16325  is_tablespace= 1;
16326  break;
16327  }
16328  case (DROP_LOGFILE_GROUP):
16329  {
16330  error= ER_DROP_FILEGROUP_FAILED;
16331  errmsg= "LOGFILE GROUP";
16333  dict->getLogfileGroup(alter_info->logfile_group_name);
16334  table_id= lg.getObjectId();
16335  table_version= lg.getObjectVersion();
16336  if (dict->dropLogfileGroup(lg))
16337  {
16338  goto ndberror;
16339  }
16340  break;
16341  }
16342  case (CHANGE_FILE_TABLESPACE):
16343  {
16344  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
16345  }
16346  case (ALTER_ACCESS_MODE_TABLESPACE):
16347  {
16348  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
16349  }
16350  default:
16351  {
16352  DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
16353  }
16354  }
16355  if (is_tablespace)
16356  ndbcluster_log_schema_op(thd,
16357  thd->query(), thd->query_length(),
16358  "", alter_info->tablespace_name,
16359  table_id, table_version,
16360  SOT_TABLESPACE, NULL, NULL);
16361  else
16362  ndbcluster_log_schema_op(thd,
16363  thd->query(), thd->query_length(),
16364  "", alter_info->logfile_group_name,
16365  table_id, table_version,
16366  SOT_LOGFILE_GROUP, NULL, NULL);
16367  DBUG_RETURN(FALSE);
16368 
16369 ndberror:
16370  err= dict->getNdbError();
16371 ndberror2:
16372  ndb_to_mysql_error(&err);
16373 
16374  my_error(error, MYF(0), errmsg);
16375  DBUG_RETURN(1);
16376 }
16377 
16378 
16379 bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
16380 {
16381  THD *thd= current_thd;
16382  Ndb *ndb;
16383  NDBDICT *dict;
16384  int err;
16385  DBUG_ENTER("ha_ndbcluster::get_no_parts");
16386  LINT_INIT(err);
16387 
16388  set_dbname(name);
16389  set_tabname(name);
16390  for (;;)
16391  {
16392  if (check_ndb_connection(thd))
16393  {
16394  err= HA_ERR_NO_CONNECTION;
16395  break;
16396  }
16397  ndb= get_ndb(thd);
16398  ndb->setDatabaseName(m_dbname);
16399  Ndb_table_guard ndbtab_g(dict= ndb->getDictionary(), m_tabname);
16400  if (!ndbtab_g.get_table())
16401  ERR_BREAK(dict->getNdbError(), err);
16402  *no_parts= ndbtab_g.get_table()->getFragmentCount();
16403  DBUG_RETURN(FALSE);
16404  }
16405 
16406  print_error(err, MYF(0));
16407  DBUG_RETURN(TRUE);
16408 }
16409 
16410 static int ndbcluster_fill_files_table(handlerton *hton,
16411  THD *thd,
16412  TABLE_LIST *tables,
16413  Item *cond)
16414 {
16415  TABLE* table= tables->table;
16416  Ndb *ndb= check_ndb_in_thd(thd);
16419  NdbError ndberr;
16420  uint i;
16421  DBUG_ENTER("ndbcluster_fill_files_table");
16422 
16424  ndberr= dict->getNdbError();
16425  if (ndberr.classification != NdbError::NoError)
16426  ERR_RETURN(ndberr);
16427 
16428  for (i= 0; i < dflist.count; i++)
16429  {
16432  uint id;
16433 
16434  g_ndb_cluster_connection->init_get_next_node(iter);
16435 
16436  while ((id= g_ndb_cluster_connection->get_next_alive_node(iter)))
16437  {
16438  init_fill_schema_files_row(table);
16439  NdbDictionary::Datafile df= dict->getDatafile(id, elt.name);
16440  ndberr= dict->getNdbError();
16441  if(ndberr.classification != NdbError::NoError)
16442  {
16443  if (ndberr.classification == NdbError::SchemaError)
16444  continue;
16445 
16447  continue;
16448 
16449  ERR_RETURN(ndberr);
16450  }
16451  NdbDictionary::Tablespace ts= dict->getTablespace(df.getTablespace());
16452  ndberr= dict->getNdbError();
16453  if (ndberr.classification != NdbError::NoError)
16454  {
16455  if (ndberr.classification == NdbError::SchemaError)
16456  continue;
16457  ERR_RETURN(ndberr);
16458  }
16459 
16460  table->field[IS_FILES_FILE_NAME]->set_notnull();
16461  table->field[IS_FILES_FILE_NAME]->store(elt.name, strlen(elt.name),
16462  system_charset_info);
16463  table->field[IS_FILES_FILE_TYPE]->set_notnull();
16464  table->field[IS_FILES_FILE_TYPE]->store("DATAFILE",8,
16465  system_charset_info);
16466  table->field[IS_FILES_TABLESPACE_NAME]->set_notnull();
16467  table->field[IS_FILES_TABLESPACE_NAME]->store(df.getTablespace(),
16468  strlen(df.getTablespace()),
16469  system_charset_info);
16470  table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
16471  table->field[IS_FILES_LOGFILE_GROUP_NAME]->
16472  store(ts.getDefaultLogfileGroup(),
16473  strlen(ts.getDefaultLogfileGroup()),
16474  system_charset_info);
16475  table->field[IS_FILES_ENGINE]->set_notnull();
16476  table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
16477  ndbcluster_hton_name_length,
16478  system_charset_info);
16479 
16480  table->field[IS_FILES_FREE_EXTENTS]->set_notnull();
16481  table->field[IS_FILES_FREE_EXTENTS]->store(df.getFree()
16482  / ts.getExtentSize(), true);
16483  table->field[IS_FILES_TOTAL_EXTENTS]->set_notnull();
16484  table->field[IS_FILES_TOTAL_EXTENTS]->store(df.getSize()
16485  / ts.getExtentSize(), true);
16486  table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
16487  table->field[IS_FILES_EXTENT_SIZE]->store(ts.getExtentSize(), true);
16488  table->field[IS_FILES_INITIAL_SIZE]->set_notnull();
16489  table->field[IS_FILES_INITIAL_SIZE]->store(df.getSize(), true);
16490  table->field[IS_FILES_MAXIMUM_SIZE]->set_notnull();
16491  table->field[IS_FILES_MAXIMUM_SIZE]->store(df.getSize(), true);
16492  table->field[IS_FILES_VERSION]->set_notnull();
16493  table->field[IS_FILES_VERSION]->store(df.getObjectVersion(), true);
16494 
16495  table->field[IS_FILES_ROW_FORMAT]->set_notnull();
16496  table->field[IS_FILES_ROW_FORMAT]->store("FIXED", 5, system_charset_info);
16497 
16498  char extra[30];
16499  int len= my_snprintf(extra, sizeof(extra), "CLUSTER_NODE=%u", id);
16500  table->field[IS_FILES_EXTRA]->set_notnull();
16501  table->field[IS_FILES_EXTRA]->store(extra, len, system_charset_info);
16502  schema_table_store_record(thd, table);
16503  }
16504  }
16505 
16508  ndberr= dict->getNdbError();
16509  if (ndberr.classification != NdbError::NoError)
16510  ERR_RETURN(ndberr);
16511 
16512  for (i= 0; i < tslist.count; i++)
16513  {
16515 
16516  NdbDictionary::Tablespace ts= dict->getTablespace(elt.name);
16517  ndberr= dict->getNdbError();
16518  if (ndberr.classification != NdbError::NoError)
16519  {
16520  if (ndberr.classification == NdbError::SchemaError)
16521  continue;
16522  ERR_RETURN(ndberr);
16523  }
16524 
16525  init_fill_schema_files_row(table);
16526  table->field[IS_FILES_FILE_TYPE]->set_notnull();
16527  table->field[IS_FILES_FILE_TYPE]->store("TABLESPACE", 10,
16528  system_charset_info);
16529 
16530  table->field[IS_FILES_TABLESPACE_NAME]->set_notnull();
16531  table->field[IS_FILES_TABLESPACE_NAME]->store(elt.name,
16532  strlen(elt.name),
16533  system_charset_info);
16534  table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
16535  table->field[IS_FILES_LOGFILE_GROUP_NAME]->
16536  store(ts.getDefaultLogfileGroup(),
16537  strlen(ts.getDefaultLogfileGroup()),
16538  system_charset_info);
16539 
16540  table->field[IS_FILES_ENGINE]->set_notnull();
16541  table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
16542  ndbcluster_hton_name_length,
16543  system_charset_info);
16544 
16545  table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
16546  table->field[IS_FILES_EXTENT_SIZE]->store(ts.getExtentSize(), true);
16547 
16548  table->field[IS_FILES_VERSION]->set_notnull();
16549  table->field[IS_FILES_VERSION]->store(ts.getObjectVersion(), true);
16550 
16551  schema_table_store_record(thd, table);
16552  }
16553 
16556  ndberr= dict->getNdbError();
16557  if (ndberr.classification != NdbError::NoError)
16558  ERR_RETURN(ndberr);
16559 
16560  for (i= 0; i < uflist.count; i++)
16561  {
16564  unsigned id;
16565 
16566  g_ndb_cluster_connection->init_get_next_node(iter);
16567 
16568  while ((id= g_ndb_cluster_connection->get_next_alive_node(iter)))
16569  {
16570  NdbDictionary::Undofile uf= dict->getUndofile(id, elt.name);
16571  ndberr= dict->getNdbError();
16572  if (ndberr.classification != NdbError::NoError)
16573  {
16574  if (ndberr.classification == NdbError::SchemaError)
16575  continue;
16577  continue;
16578  ERR_RETURN(ndberr);
16579  }
16581  dict->getLogfileGroup(uf.getLogfileGroup());
16582  ndberr= dict->getNdbError();
16583  if (ndberr.classification != NdbError::NoError)
16584  {
16585  if (ndberr.classification == NdbError::SchemaError)
16586  continue;
16587  ERR_RETURN(ndberr);
16588  }
16589 
16590  init_fill_schema_files_row(table);
16591  table->field[IS_FILES_FILE_NAME]->set_notnull();
16592  table->field[IS_FILES_FILE_NAME]->store(elt.name, strlen(elt.name),
16593  system_charset_info);
16594  table->field[IS_FILES_FILE_TYPE]->set_notnull();
16595  table->field[IS_FILES_FILE_TYPE]->store("UNDO LOG", 8,
16596  system_charset_info);
16598  uf.getLogfileGroupId(&objid);
16599  table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
16600  table->field[IS_FILES_LOGFILE_GROUP_NAME]->store(uf.getLogfileGroup(),
16601  strlen(uf.getLogfileGroup()),
16602  system_charset_info);
16603  table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->set_notnull();
16604  table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->store(objid.getObjectId(), true);
16605  table->field[IS_FILES_ENGINE]->set_notnull();
16606  table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
16607  ndbcluster_hton_name_length,
16608  system_charset_info);
16609 
16610  table->field[IS_FILES_TOTAL_EXTENTS]->set_notnull();
16611  table->field[IS_FILES_TOTAL_EXTENTS]->store(uf.getSize()/4, true);
16612  table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
16613  table->field[IS_FILES_EXTENT_SIZE]->store(4, true);
16614 
16615  table->field[IS_FILES_INITIAL_SIZE]->set_notnull();
16616  table->field[IS_FILES_INITIAL_SIZE]->store(uf.getSize(), true);
16617  table->field[IS_FILES_MAXIMUM_SIZE]->set_notnull();
16618  table->field[IS_FILES_MAXIMUM_SIZE]->store(uf.getSize(), true);
16619 
16620  table->field[IS_FILES_VERSION]->set_notnull();
16621  table->field[IS_FILES_VERSION]->store(uf.getObjectVersion(), true);
16622 
16623  char extra[100];
16624  int len= my_snprintf(extra,sizeof(extra),"CLUSTER_NODE=%u;UNDO_BUFFER_SIZE=%lu",
16625  id, (ulong) lfg.getUndoBufferSize());
16626  table->field[IS_FILES_EXTRA]->set_notnull();
16627  table->field[IS_FILES_EXTRA]->store(extra, len, system_charset_info);
16628  schema_table_store_record(thd, table);
16629  }
16630  }
16631 
16632  // now for LFGs
16635  ndberr= dict->getNdbError();
16636  if (ndberr.classification != NdbError::NoError)
16637  ERR_RETURN(ndberr);
16638 
16639  for (i= 0; i < lfglist.count; i++)
16640  {
16642 
16643  NdbDictionary::LogfileGroup lfg= dict->getLogfileGroup(elt.name);
16644  ndberr= dict->getNdbError();
16645  if (ndberr.classification != NdbError::NoError)
16646  {
16647  if (ndberr.classification == NdbError::SchemaError)
16648  continue;
16649  ERR_RETURN(ndberr);
16650  }
16651 
16652  init_fill_schema_files_row(table);
16653  table->field[IS_FILES_FILE_TYPE]->set_notnull();
16654  table->field[IS_FILES_FILE_TYPE]->store("UNDO LOG", 8,
16655  system_charset_info);
16656 
16657  table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
16658  table->field[IS_FILES_LOGFILE_GROUP_NAME]->store(elt.name,
16659  strlen(elt.name),
16660  system_charset_info);
16661  table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->set_notnull();
16662  table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->store(lfg.getObjectId(), true);
16663  table->field[IS_FILES_ENGINE]->set_notnull();
16664  table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
16665  ndbcluster_hton_name_length,
16666  system_charset_info);
16667 
16668  table->field[IS_FILES_FREE_EXTENTS]->set_notnull();
16669  table->field[IS_FILES_FREE_EXTENTS]->store(lfg.getUndoFreeWords(), true);
16670  table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
16671  table->field[IS_FILES_EXTENT_SIZE]->store(4, true);
16672 
16673  table->field[IS_FILES_VERSION]->set_notnull();
16674  table->field[IS_FILES_VERSION]->store(lfg.getObjectVersion(), true);
16675 
16676  char extra[100];
16677  int len= my_snprintf(extra,sizeof(extra),
16678  "UNDO_BUFFER_SIZE=%lu",
16679  (ulong) lfg.getUndoBufferSize());
16680  table->field[IS_FILES_EXTRA]->set_notnull();
16681  table->field[IS_FILES_EXTRA]->store(extra, len, system_charset_info);
16682  schema_table_store_record(thd, table);
16683  }
16684  DBUG_RETURN(0);
16685 }
16686 
16687 static int show_ndb_vars(THD *thd, SHOW_VAR *var, char *buff)
16688 {
16689  if (!check_ndb_in_thd(thd))
16690  return -1;
16691  struct st_ndb_status *st;
16692  SHOW_VAR *st_var;
16693  {
16694  char *mem= (char*)sql_alloc(sizeof(struct st_ndb_status) +
16695  sizeof(ndb_status_variables_dynamic));
16696  st= new (mem) st_ndb_status;
16697  st_var= (SHOW_VAR*)(mem + sizeof(struct st_ndb_status));
16698  memcpy(st_var, &ndb_status_variables_dynamic, sizeof(ndb_status_variables_dynamic));
16699  int i= 0;
16700  SHOW_VAR *tmp= &(ndb_status_variables_dynamic[0]);
16701  for (; tmp->value; tmp++, i++)
16702  st_var[i].value= mem + (tmp->value - (char*)&g_ndb_status);
16703  }
16704  {
16705  Thd_ndb *thd_ndb= get_thd_ndb(thd);
16706  Ndb_cluster_connection *c= thd_ndb->connection;
16707  update_status_variables(thd_ndb, st, c);
16708  }
16709  var->type= SHOW_ARRAY;
16710  var->value= (char *) st_var;
16711  return 0;
16712 }
16713 
16714 SHOW_VAR ndb_status_variables_export[]= {
16715  {"Ndb", (char*) &show_ndb_vars, SHOW_FUNC},
16716  {"Ndb_conflict", (char*) &ndb_status_conflict_variables, SHOW_ARRAY},
16717  {"Ndb", (char*) &ndb_status_injector_variables, SHOW_ARRAY},
16718  {"Ndb", (char*) &ndb_status_slave_variables, SHOW_ARRAY},
16719  {"Ndb", (char*) &show_ndb_server_api_stats, SHOW_FUNC},
16720  {"Ndb_index_stat", (char*) &ndb_status_index_stat_variables, SHOW_ARRAY},
16721  {NullS, NullS, SHOW_LONG}
16722 };
16723 
16724 static MYSQL_SYSVAR_ULONG(
16725  cache_check_time, /* name */
16726  opt_ndb_cache_check_time, /* var */
16727  PLUGIN_VAR_RQCMDARG,
16728  "A dedicated thread is created to, at the given "
16729  "millisecond interval, invalidate the query cache "
16730  "if another MySQL server in the cluster has changed "
16731  "the data in the database.",
16732  NULL, /* check func. */
16733  NULL, /* update func. */
16734  0, /* default */
16735  0, /* min */
16736  ONE_YEAR_IN_SECONDS, /* max */
16737  0 /* block */
16738 );
16739 
16740 
16741 static MYSQL_SYSVAR_ULONG(
16742  extra_logging, /* name */
16743  opt_ndb_extra_logging, /* var */
16744  PLUGIN_VAR_OPCMDARG,
16745  "Turn on more logging in the error log.",
16746  NULL, /* check func. */
16747  NULL, /* update func. */
16748  1, /* default */
16749  0, /* min */
16750  0, /* max */
16751  0 /* block */
16752 );
16753 
16754 
16755 static MYSQL_SYSVAR_ULONG(
16756  wait_connected, /* name */
16757  opt_ndb_wait_connected, /* var */
16758  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16759  "Time (in seconds) for mysqld to wait for connection "
16760  "to cluster management and data nodes.",
16761  NULL, /* check func. */
16762  NULL, /* update func. */
16763  0, /* default */
16764  0, /* min */
16765  ONE_YEAR_IN_SECONDS, /* max */
16766  0 /* block */
16767 );
16768 
16769 
16770 static MYSQL_SYSVAR_ULONG(
16771  wait_setup, /* name */
16772  opt_ndb_wait_setup, /* var */
16773  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16774  "Time (in seconds) for mysqld to wait for setup to "
16775  "complete (0 = no wait)",
16776  NULL, /* check func. */
16777  NULL, /* update func. */
16778  15, /* default */
16779  0, /* min */
16780  ONE_YEAR_IN_SECONDS, /* max */
16781  0 /* block */
16782 );
16783 
16784 
16785 static MYSQL_SYSVAR_UINT(
16786  cluster_connection_pool, /* name */
16787  opt_ndb_cluster_connection_pool, /* var */
16788  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16789  "Pool of cluster connections to be used by mysql server.",
16790  NULL, /* check func. */
16791  NULL, /* update func. */
16792  1, /* default */
16793  1, /* min */
16794  63, /* max */
16795  0 /* block */
16796 );
16797 
16798 /* should be in index_stat.h */
16799 
16800 extern int
16801 ndb_index_stat_option_check(MYSQL_THD,
16802  struct st_mysql_sys_var *var,
16803  void *save,
16804  struct st_mysql_value *value);
16805 extern void
16806 ndb_index_stat_option_update(MYSQL_THD,
16807  struct st_mysql_sys_var *var,
16808  void *var_ptr,
16809  const void *save);
16810 
16811 extern char ndb_index_stat_option_buf[];
16812 
16813 static MYSQL_SYSVAR_STR(
16814  index_stat_option, /* name */
16815  opt_ndb_index_stat_option, /* var */
16816  PLUGIN_VAR_RQCMDARG,
16817  "Comma-separated tunable options for ndb index statistics",
16818  ndb_index_stat_option_check, /* check func. */
16819  ndb_index_stat_option_update, /* update func. */
16820  ndb_index_stat_option_buf
16821 );
16822 
16823 
16824 ulong opt_ndb_report_thresh_binlog_epoch_slip;
16825 static MYSQL_SYSVAR_ULONG(
16826  report_thresh_binlog_epoch_slip, /* name */
16827  opt_ndb_report_thresh_binlog_epoch_slip,/* var */
16828  PLUGIN_VAR_RQCMDARG,
16829  "Threshold on number of epochs to be behind before reporting binlog "
16830  "status. E.g. 3 means that if the difference between what epoch has "
16831  "been received from the storage nodes and what has been applied to "
16832  "the binlog is 3 or more, a status message will be sent to the cluster "
16833  "log.",
16834  NULL, /* check func. */
16835  NULL, /* update func. */
16836  3, /* default */
16837  0, /* min */
16838  256, /* max */
16839  0 /* block */
16840 );
16841 
16842 
16843 ulong opt_ndb_report_thresh_binlog_mem_usage;
16844 static MYSQL_SYSVAR_ULONG(
16845  report_thresh_binlog_mem_usage, /* name */
16846  opt_ndb_report_thresh_binlog_mem_usage,/* var */
16847  PLUGIN_VAR_RQCMDARG,
16848  "Threshold on percentage of free memory before reporting binlog "
16849  "status. E.g. 10 means that if amount of available memory for "
16850  "receiving binlog data from the storage nodes goes below 10%, "
16851  "a status message will be sent to the cluster log.",
16852  NULL, /* check func. */
16853  NULL, /* update func. */
16854  10, /* default */
16855  0, /* min */
16856  100, /* max */
16857  0 /* block */
16858 );
16859 
16860 
16861 my_bool opt_ndb_log_update_as_write;
16862 static MYSQL_SYSVAR_BOOL(
16863  log_update_as_write, /* name */
16864  opt_ndb_log_update_as_write, /* var */
16865  PLUGIN_VAR_OPCMDARG,
16866  "For efficiency log only after image as a write event. "
16867  "Ignore before image. This may cause compatability problems if "
16868  "replicating to other storage engines than ndbcluster.",
16869  NULL, /* check func. */
16870  NULL, /* update func. */
16871  1 /* default */
16872 );
16873 
16874 
16875 my_bool opt_ndb_log_updated_only;
16876 static MYSQL_SYSVAR_BOOL(
16877  log_updated_only, /* name */
16878  opt_ndb_log_updated_only, /* var */
16879  PLUGIN_VAR_OPCMDARG,
16880  "For efficiency log only updated columns. Columns are considered "
16881  "as \"updated\" even if they are updated with the same value. "
16882  "This may cause compatability problems if "
16883  "replicating to other storage engines than ndbcluster.",
16884  NULL, /* check func. */
16885  NULL, /* update func. */
16886  1 /* default */
16887 );
16888 
16889 
16890 my_bool opt_ndb_log_orig;
16891 static MYSQL_SYSVAR_BOOL(
16892  log_orig, /* name */
16893  opt_ndb_log_orig, /* var */
16894  PLUGIN_VAR_OPCMDARG,
16895  "Log originating server id and epoch in ndb_binlog_index. Each epoch "
16896  "may in this case have multiple rows in ndb_binlog_index, one for "
16897  "each originating epoch.",
16898  NULL, /* check func. */
16899  NULL, /* update func. */
16900  0 /* default */
16901 );
16902 
16903 
16904 my_bool opt_ndb_log_bin;
16905 static MYSQL_SYSVAR_BOOL(
16906  log_bin, /* name */
16907  opt_ndb_log_bin, /* var */
16908  PLUGIN_VAR_OPCMDARG,
16909  "Log ndb tables in the binary log. Option only has meaning if "
16910  "the binary log has been turned on for the server.",
16911  NULL, /* check func. */
16912  NULL, /* update func. */
16913  1 /* default */
16914 );
16915 
16916 
16917 my_bool opt_ndb_log_binlog_index;
16918 static MYSQL_SYSVAR_BOOL(
16919  log_binlog_index, /* name */
16920  opt_ndb_log_binlog_index, /* var */
16921  PLUGIN_VAR_OPCMDARG,
16922  "Insert mapping between epochs and binlog positions into the "
16923  "ndb_binlog_index table.",
16924  NULL, /* check func. */
16925  NULL, /* update func. */
16926  1 /* default */
16927 );
16928 
16929 
16930 static my_bool opt_ndb_log_empty_epochs;
16931 static MYSQL_SYSVAR_BOOL(
16932  log_empty_epochs, /* name */
16933  opt_ndb_log_empty_epochs, /* var */
16934  PLUGIN_VAR_OPCMDARG,
16935  "",
16936  NULL, /* check func. */
16937  NULL, /* update func. */
16938  0 /* default */
16939 );
16940 
16941 bool ndb_log_empty_epochs(void)
16942 {
16943  return opt_ndb_log_empty_epochs;
16944 }
16945 
16946 my_bool opt_ndb_log_apply_status;
16947 static MYSQL_SYSVAR_BOOL(
16948  log_apply_status, /* name */
16949  opt_ndb_log_apply_status, /* var */
16950  PLUGIN_VAR_OPCMDARG,
16951  "Log ndb_apply_status updates from Master in the Binlog",
16952  NULL, /* check func. */
16953  NULL, /* update func. */
16954  0 /* default */
16955 );
16956 
16957 
16958 static MYSQL_SYSVAR_STR(
16959  connectstring, /* name */
16960  opt_ndb_connectstring, /* var */
16961  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16962  "Connect string for ndbcluster.",
16963  NULL, /* check func. */
16964  NULL, /* update func. */
16965  NULL /* default */
16966 );
16967 
16968 
16969 static MYSQL_SYSVAR_STR(
16970  mgmd_host, /* name */
16971  opt_ndb_connectstring, /* var */
16972  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16973  "Same as --ndb-connectstring",
16974  NULL, /* check func. */
16975  NULL, /* update func. */
16976  NULL /* default */
16977 );
16978 
16979 
16980 static MYSQL_SYSVAR_UINT(
16981  nodeid, /* name */
16982  opt_ndb_nodeid, /* var */
16983  PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
16984  "Set nodeid for this node. Overrides node id specified "
16985  "in --ndb-connectstring.",
16986  NULL, /* check func. */
16987  NULL, /* update func. */
16988  0, /* default */
16989  0, /* min */
16990  MAX_NODES_ID, /* max */
16991  0 /* block */
16992 );
16993 
16994 #ifndef DBUG_OFF
16995 
16996 static
16997 void
16998 dbug_check_shares(THD*, st_mysql_sys_var*, void*, const void*)
16999 {
17000  sql_print_information("dbug_check_shares");
17001  for (uint i= 0; i < ndbcluster_open_tables.records; i++)
17002  {
17003  NDB_SHARE * share = (NDB_SHARE*)my_hash_element(&ndbcluster_open_tables, i);
17004  sql_print_information(" %s.%s: state: %s(%u) use_count: %u",
17005  share->db, share->table_name,
17006  get_share_state_string(share->state),
17007  (unsigned)share->state,
17008  share->use_count);
17009  }
17010 
17014  for (uint i= 0; i < ndbcluster_open_tables.records; i++)
17015  {
17016  NDB_SHARE * share = (NDB_SHARE*)my_hash_element(&ndbcluster_open_tables, i);
17017  DBUG_ASSERT(strcmp(share->db, "mysql") == 0);
17018  }
17019 }
17020 
17021 static MYSQL_THDVAR_UINT(
17022  check_shares, /* name */
17023  PLUGIN_VAR_RQCMDARG,
17024  "Debug, only...check that no shares are lingering...",
17025  NULL, /* check func */
17026  dbug_check_shares, /* update func */
17027  0, /* default */
17028  0, /* min */
17029  1, /* max */
17030  0 /* block */
17031 );
17032 
17033 #endif
17034 
17035 static struct st_mysql_sys_var* system_variables[]= {
17036  MYSQL_SYSVAR(cache_check_time),
17037  MYSQL_SYSVAR(extra_logging),
17038  MYSQL_SYSVAR(wait_connected),
17039  MYSQL_SYSVAR(wait_setup),
17040  MYSQL_SYSVAR(cluster_connection_pool),
17041  MYSQL_SYSVAR(report_thresh_binlog_mem_usage),
17042  MYSQL_SYSVAR(report_thresh_binlog_epoch_slip),
17043  MYSQL_SYSVAR(log_update_as_write),
17044  MYSQL_SYSVAR(log_updated_only),
17045  MYSQL_SYSVAR(log_orig),
17046  MYSQL_SYSVAR(distribution),
17047  MYSQL_SYSVAR(autoincrement_prefetch_sz),
17048  MYSQL_SYSVAR(force_send),
17049  MYSQL_SYSVAR(use_exact_count),
17050  MYSQL_SYSVAR(use_transactions),
17051  MYSQL_SYSVAR(use_copying_alter_table),
17052  MYSQL_SYSVAR(optimized_node_selection),
17053  MYSQL_SYSVAR(batch_size),
17054  MYSQL_SYSVAR(optimization_delay),
17055  MYSQL_SYSVAR(index_stat_enable),
17056  MYSQL_SYSVAR(index_stat_option),
17057  MYSQL_SYSVAR(index_stat_cache_entries),
17058  MYSQL_SYSVAR(index_stat_update_freq),
17059  MYSQL_SYSVAR(table_no_logging),
17060  MYSQL_SYSVAR(table_temporary),
17061  MYSQL_SYSVAR(log_bin),
17062  MYSQL_SYSVAR(log_binlog_index),
17063  MYSQL_SYSVAR(log_empty_epochs),
17064  MYSQL_SYSVAR(log_apply_status),
17065  MYSQL_SYSVAR(connectstring),
17066  MYSQL_SYSVAR(mgmd_host),
17067  MYSQL_SYSVAR(nodeid),
17068  MYSQL_SYSVAR(blob_read_batch_bytes),
17069  MYSQL_SYSVAR(blob_write_batch_bytes),
17070  MYSQL_SYSVAR(deferred_constraints),
17071  MYSQL_SYSVAR(join_pushdown),
17072 #ifndef DBUG_OFF
17073  MYSQL_SYSVAR(check_shares),
17074 #endif
17075  NULL
17076 };
17077 
17078 struct st_mysql_storage_engine ndbcluster_storage_engine=
17079 { MYSQL_HANDLERTON_INTERFACE_VERSION };
17080 
17081 
17082 #include "ha_ndbinfo.h"
17083 
17084 extern struct st_mysql_sys_var* ndbinfo_system_variables[];
17085 
17086 struct st_mysql_storage_engine ndbinfo_storage_engine=
17087 { MYSQL_HANDLERTON_INTERFACE_VERSION };
17088 
17089 mysql_declare_plugin(ndbcluster)
17090 {
17091  MYSQL_STORAGE_ENGINE_PLUGIN,
17092  &ndbcluster_storage_engine,
17093  ndbcluster_hton_name,
17094  "MySQL AB",
17095  "Clustered, fault-tolerant tables",
17096  PLUGIN_LICENSE_GPL,
17097  ndbcluster_init, /* plugin init */
17098  NULL, /* plugin deinit */
17099  0x0100, /* plugin version */
17100  ndb_status_variables_export,/* status variables */
17101  system_variables, /* system variables */
17102  NULL, /* config options */
17103  0 /* flags */
17104 },
17105 {
17106  MYSQL_STORAGE_ENGINE_PLUGIN,
17107  &ndbinfo_storage_engine,
17108  "ndbinfo",
17109  "Sun Microsystems Inc.",
17110  "MySQL Cluster system information storage engine",
17111  PLUGIN_LICENSE_GPL,
17112  ndbinfo_init, /* plugin init */
17113  ndbinfo_deinit, /* plugin deinit */
17114  0x0001, /* plugin version */
17115  NULL, /* status variables */
17116  ndbinfo_system_variables, /* system variables */
17117  NULL, /* config options */
17118  0 /* flags */
17119 }
17120 mysql_declare_plugin_end;
17121 
17122 #endif