mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / ha_ndbcluster.cc
blob44015f3e2b4693b09a8e1139cd6a4b409315e49b
1 /* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
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.
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.
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 */
16 /**
17 @file
19 @brief
20 This file defines the NDB Cluster handler: the interface between
21 MySQL and NDB Cluster
24 #ifdef USE_PRAGMA_IMPLEMENTATION
25 #pragma implementation // gcc: Class implementation
26 #endif
28 #include "mysql_priv.h"
29 #include "rpl_mi.h"
31 #include <my_dir.h>
32 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
33 #include "ha_ndbcluster.h"
34 #include <ndbapi/NdbApi.hpp>
35 #include "ha_ndbcluster_cond.h"
36 #include <../util/Bitmask.hpp>
37 #include <ndbapi/NdbIndexStat.hpp>
39 #include "ha_ndbcluster_binlog.h"
40 #include "ha_ndbcluster_tables.h"
42 #include <mysql/plugin.h>
44 #ifdef ndb_dynamite
45 #undef assert
46 #define assert(x) do { if(x) break; ::printf("%s %d: assert failed: %s\n", __FILE__, __LINE__, #x); ::fflush(stdout); ::signal(SIGABRT,SIG_DFL); ::abort(); ::kill(::getpid(),6); ::kill(::getpid(),9); } while (0)
47 #endif
49 // options from from mysqld.cc
50 extern my_bool opt_ndb_optimized_node_selection;
51 extern const char *opt_ndbcluster_connectstring;
52 extern ulong opt_ndb_cache_check_time;
54 // ndb interface initialization/cleanup
55 #ifdef __cplusplus
56 extern "C" {
57 #endif
58 extern void ndb_init_internal();
59 extern void ndb_end_internal();
60 #ifdef __cplusplus
62 #endif
64 const char *ndb_distribution_names[]= {"KEYHASH", "LINHASH", NullS};
65 TYPELIB ndb_distribution_typelib= { array_elements(ndb_distribution_names)-1,
66 "", ndb_distribution_names, NULL };
67 const char *opt_ndb_distribution= ndb_distribution_names[ND_KEYHASH];
68 enum ndb_distribution opt_ndb_distribution_id= ND_KEYHASH;
70 // Default value for parallelism
71 static const int parallelism= 0;
73 // Default value for max number of transactions
74 // createable against NDB from this handler
75 static const int max_transactions= 3; // should really be 2 but there is a transaction to much allocated when loch table is used
77 static uint ndbcluster_partition_flags();
78 static uint ndbcluster_alter_table_flags(uint flags);
79 static int ndbcluster_init(void *);
80 static int ndbcluster_end(handlerton *hton, ha_panic_function flag);
81 static bool ndbcluster_show_status(handlerton *hton, THD*,
82 stat_print_fn *,
83 enum ha_stat_type);
84 static int ndbcluster_alter_tablespace(handlerton *hton,
85 THD* thd,
86 st_alter_tablespace *info);
87 static int ndbcluster_fill_files_table(handlerton *hton,
88 THD *thd,
89 TABLE_LIST *tables,
90 COND *cond);
92 handlerton *ndbcluster_hton;
94 static handler *ndbcluster_create_handler(handlerton *hton,
95 TABLE_SHARE *table,
96 MEM_ROOT *mem_root)
98 return new (mem_root) ha_ndbcluster(hton, table);
101 static uint ndbcluster_partition_flags()
103 return (HA_CAN_PARTITION | HA_CAN_UPDATE_PARTITION_KEY |
104 HA_CAN_PARTITION_UNIQUE | HA_USE_AUTO_PARTITION);
107 static uint ndbcluster_alter_table_flags(uint flags)
109 if (flags & ALTER_DROP_PARTITION)
110 return 0;
111 else
112 return (HA_ONLINE_ADD_INDEX | HA_ONLINE_DROP_INDEX |
113 HA_ONLINE_ADD_UNIQUE_INDEX | HA_ONLINE_DROP_UNIQUE_INDEX |
114 HA_PARTITION_FUNCTION_SUPPORTED);
118 #define NDB_AUTO_INCREMENT_RETRIES 10
120 #define ERR_PRINT(err) \
121 DBUG_PRINT("error", ("%d message: %s", err.code, err.message))
123 #define ERR_RETURN(err) \
125 const NdbError& tmp= err; \
126 set_ndb_err(current_thd, tmp); \
127 DBUG_RETURN(ndb_to_mysql_error(&tmp)); \
130 #define ERR_BREAK(err, code) \
132 const NdbError& tmp= err; \
133 set_ndb_err(current_thd, tmp); \
134 code= ndb_to_mysql_error(&tmp); \
135 break; \
138 static int ndbcluster_inited= 0;
139 int ndbcluster_terminating= 0;
141 static Ndb* g_ndb= NULL;
142 Ndb_cluster_connection* g_ndb_cluster_connection= NULL;
143 uchar g_node_id_map[max_ndb_nodes];
145 /// Handler synchronization
146 pthread_mutex_t ndbcluster_mutex;
148 /// Table lock handling
149 HASH ndbcluster_open_tables;
151 static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
152 my_bool not_used __attribute__((unused)));
153 #ifdef HAVE_NDB_BINLOG
154 static int rename_share(NDB_SHARE *share, const char *new_key);
155 #endif
156 static int ndb_get_table_statistics(ha_ndbcluster*, bool, Ndb*, const NDBTAB *,
157 struct Ndb_statistics *);
160 // Util thread variables
161 pthread_t ndb_util_thread;
162 int ndb_util_thread_running= 0;
163 pthread_mutex_t LOCK_ndb_util_thread;
164 pthread_cond_t COND_ndb_util_thread;
165 pthread_cond_t COND_ndb_util_ready;
166 pthread_handler_t ndb_util_thread_func(void *arg);
167 ulong ndb_cache_check_time;
170 Dummy buffer to read zero pack_length fields
171 which are mapped to 1 char.
173 static uint32 dummy_buf;
176 Stats that can be retrieved from ndb.
179 struct Ndb_statistics {
180 Uint64 row_count;
181 Uint64 commit_count;
182 Uint64 row_size;
183 Uint64 fragment_memory;
186 /* Status variables shown with 'show status like 'Ndb%' */
188 static long ndb_cluster_node_id= 0;
189 static const char * ndb_connected_host= 0;
190 static long ndb_connected_port= 0;
191 static long ndb_number_of_replicas= 0;
192 long ndb_number_of_data_nodes= 0;
193 long ndb_number_of_ready_data_nodes= 0;
194 long ndb_connect_count= 0;
196 static int update_status_variables(Ndb_cluster_connection *c)
198 ndb_cluster_node_id= c->node_id();
199 ndb_connected_port= c->get_connected_port();
200 ndb_connected_host= c->get_connected_host();
201 ndb_number_of_replicas= 0;
202 ndb_number_of_ready_data_nodes= c->get_no_ready();
203 ndb_number_of_data_nodes= c->no_db_nodes();
204 ndb_connect_count= c->get_connect_count();
205 return 0;
208 SHOW_VAR ndb_status_variables[]= {
209 {"cluster_node_id", (char*) &ndb_cluster_node_id, SHOW_LONG},
210 {"config_from_host", (char*) &ndb_connected_host, SHOW_CHAR_PTR},
211 {"config_from_port", (char*) &ndb_connected_port, SHOW_LONG},
212 // {"number_of_replicas", (char*) &ndb_number_of_replicas, SHOW_LONG},
213 {"number_of_data_nodes",(char*) &ndb_number_of_data_nodes, SHOW_LONG},
214 {NullS, NullS, SHOW_LONG}
218 Error handling functions
221 /* Note for merge: old mapping table, moved to storage/ndb/ndberror.c */
223 static int ndb_to_mysql_error(const NdbError *ndberr)
225 /* read the mysql mapped error code */
226 int error= ndberr->mysql_code;
228 switch (error)
230 /* errors for which we do not add warnings, just return mapped error code
232 case HA_ERR_NO_SUCH_TABLE:
233 case HA_ERR_KEY_NOT_FOUND:
234 return error;
236 /* Mapping missing, go with the ndb error code*/
237 case -1:
238 error= ndberr->code;
239 break;
240 /* Mapping exists, go with the mapped code */
241 default:
242 break;
246 Push the NDB error message as warning
247 - Used to be able to use SHOW WARNINGS toget more info on what the error is
248 - Used by replication to see if the error was temporary
250 if (ndberr->status == NdbError::TemporaryError)
251 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
252 ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG),
253 ndberr->code, ndberr->message, "NDB");
254 else
255 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
256 ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
257 ndberr->code, ndberr->message, "NDB");
258 return error;
261 int execute_no_commit_ignore_no_key(ha_ndbcluster *h, NdbTransaction *trans)
263 if (trans->execute(NdbTransaction::NoCommit,
264 NdbOperation::AO_IgnoreError,
265 h->m_force_send) == -1)
266 return -1;
268 const NdbError &err= trans->getNdbError();
269 if (err.classification != NdbError::NoError &&
270 err.classification != NdbError::ConstraintViolation &&
271 err.classification != NdbError::NoDataFound)
272 return -1;
274 return 0;
277 inline
278 int execute_no_commit(ha_ndbcluster *h, NdbTransaction *trans,
279 bool force_release)
281 h->release_completed_operations(trans, force_release);
282 return h->m_ignore_no_key ?
283 execute_no_commit_ignore_no_key(h,trans) :
284 trans->execute(NdbTransaction::NoCommit,
285 NdbOperation::AbortOnError,
286 h->m_force_send);
289 inline
290 int execute_commit(ha_ndbcluster *h, NdbTransaction *trans)
292 return trans->execute(NdbTransaction::Commit,
293 NdbOperation::AbortOnError,
294 h->m_force_send);
297 inline
298 int execute_commit(THD *thd, NdbTransaction *trans)
300 return trans->execute(NdbTransaction::Commit,
301 NdbOperation::AbortOnError,
302 thd->variables.ndb_force_send);
305 inline
306 int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans,
307 bool force_release)
309 h->release_completed_operations(trans, force_release);
310 return trans->execute(NdbTransaction::NoCommit,
311 NdbOperation::AO_IgnoreError,
312 h->m_force_send);
316 Place holder for ha_ndbcluster thread specific data
318 typedef struct st_thd_ndb_share {
319 const void *key;
320 struct Ndb_local_table_statistics stat;
321 } THD_NDB_SHARE;
322 static
323 uchar *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, size_t *length,
324 my_bool not_used __attribute__((unused)))
326 *length= sizeof(thd_ndb_share->key);
327 return (uchar*) &thd_ndb_share->key;
330 Thd_ndb::Thd_ndb()
332 ndb= new Ndb(g_ndb_cluster_connection, "");
333 lock_count= 0;
334 start_stmt_count= 0;
335 count= 0;
336 trans= NULL;
337 m_error= FALSE;
338 m_error_code= 0;
339 query_state&= NDB_QUERY_NORMAL;
340 options= 0;
341 (void) hash_init(&open_tables, &my_charset_bin, 5, 0, 0,
342 (hash_get_key)thd_ndb_share_get_key, 0, 0);
345 Thd_ndb::~Thd_ndb()
347 if (ndb)
349 #ifndef DBUG_OFF
350 Ndb::Free_list_usage tmp;
351 tmp.m_name= 0;
352 while (ndb->get_free_list_usage(&tmp))
354 uint leaked= (uint) tmp.m_created - tmp.m_free;
355 if (leaked)
356 fprintf(stderr, "NDB: Found %u %s%s that %s not been released\n",
357 leaked, tmp.m_name,
358 (leaked == 1)?"":"'s",
359 (leaked == 1)?"has":"have");
361 #endif
362 delete ndb;
363 ndb= NULL;
365 changed_tables.empty();
366 hash_free(&open_tables);
369 void
370 Thd_ndb::init_open_tables()
372 count= 0;
373 m_error= FALSE;
374 m_error_code= 0;
375 my_hash_reset(&open_tables);
378 inline
379 Ndb *ha_ndbcluster::get_ndb()
381 return get_thd_ndb(current_thd)->ndb;
385 * manage uncommitted insert/deletes during transactio to get records correct
388 void ha_ndbcluster::set_rec_per_key()
390 DBUG_ENTER("ha_ndbcluster::get_status_const");
391 for (uint i=0 ; i < table_share->keys ; i++)
393 table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= 1;
395 DBUG_VOID_RETURN;
398 ha_rows ha_ndbcluster::records()
400 ha_rows retval;
401 DBUG_ENTER("ha_ndbcluster::records");
402 struct Ndb_local_table_statistics *local_info= m_table_info;
403 DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
404 ((const NDBTAB *)m_table)->getTableId(),
405 local_info->no_uncommitted_rows_count));
407 Ndb *ndb= get_ndb();
408 ndb->setDatabaseName(m_dbname);
409 struct Ndb_statistics stat;
410 if (ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat) == 0)
412 retval= stat.row_count;
414 else
416 DBUG_RETURN(HA_POS_ERROR);
419 THD *thd= current_thd;
420 if (get_thd_ndb(thd)->m_error)
421 local_info->no_uncommitted_rows_count= 0;
423 DBUG_RETURN(retval + local_info->no_uncommitted_rows_count);
426 int ha_ndbcluster::records_update()
428 if (m_ha_not_exact_count)
429 return 0;
430 DBUG_ENTER("ha_ndbcluster::records_update");
431 int result= 0;
433 struct Ndb_local_table_statistics *local_info= m_table_info;
434 DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
435 ((const NDBTAB *)m_table)->getTableId(),
436 local_info->no_uncommitted_rows_count));
438 Ndb *ndb= get_ndb();
439 struct Ndb_statistics stat;
440 if (ndb->setDatabaseName(m_dbname))
442 return my_errno= HA_ERR_OUT_OF_MEM;
444 result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat);
445 if (result == 0)
447 stats.mean_rec_length= stat.row_size;
448 stats.data_file_length= stat.fragment_memory;
449 local_info->records= stat.row_count;
453 THD *thd= current_thd;
454 if (get_thd_ndb(thd)->m_error)
455 local_info->no_uncommitted_rows_count= 0;
457 if (result == 0)
458 stats.records= local_info->records+ local_info->no_uncommitted_rows_count;
459 DBUG_RETURN(result);
462 void ha_ndbcluster::no_uncommitted_rows_execute_failure()
464 if (m_ha_not_exact_count)
465 return;
466 DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_execute_failure");
467 get_thd_ndb(current_thd)->m_error= TRUE;
468 get_thd_ndb(current_thd)->m_error_code= 0;
469 DBUG_VOID_RETURN;
472 void ha_ndbcluster::no_uncommitted_rows_update(int c)
474 if (m_ha_not_exact_count)
475 return;
476 DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_update");
477 struct Ndb_local_table_statistics *local_info= m_table_info;
478 local_info->no_uncommitted_rows_count+= c;
479 DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d",
480 ((const NDBTAB *)m_table)->getTableId(),
481 local_info->no_uncommitted_rows_count));
482 DBUG_VOID_RETURN;
485 void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd)
487 if (m_ha_not_exact_count)
488 return;
489 DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_reset");
490 Thd_ndb *thd_ndb= get_thd_ndb(thd);
491 thd_ndb->count++;
492 thd_ndb->m_error= FALSE;
493 DBUG_VOID_RETURN;
497 Sets the latest ndb error code on the thd_ndb object such that it
498 can be retrieved later to know which ndb error caused the handler
499 error.
501 static void set_ndb_err(THD *thd, const NdbError &err)
503 DBUG_ENTER("set_ndb_err");
504 ERR_PRINT(err);
506 Thd_ndb *thd_ndb= get_thd_ndb(thd);
507 if (thd_ndb == NULL)
508 DBUG_VOID_RETURN;
509 #ifdef NOT_YET
511 Check if error code is overwritten, in this case the original
512 failure cause will be lost. E.g. if 4350 error is given. So
513 push a warning so that it can be detected which is the root
514 error cause.
516 if (thd_ndb->m_query_id == thd->query_id &&
517 thd_ndb->m_error_code != 0 &&
518 thd_ndb->m_error_code != err.code)
520 char buf[FN_REFLEN];
521 ndb_error_string(thd_ndb->m_error_code, buf, sizeof(buf));
522 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
523 ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
524 thd_ndb->m_error_code, buf, "NDB");
526 #endif
527 thd_ndb->m_query_id= thd->query_id;
528 thd_ndb->m_error_code= err.code;
529 DBUG_VOID_RETURN;
532 int ha_ndbcluster::ndb_err(NdbTransaction *trans)
534 THD *thd= current_thd;
535 int res;
536 NdbError err= trans->getNdbError();
537 DBUG_ENTER("ndb_err");
539 set_ndb_err(thd, err);
541 switch (err.classification) {
542 case NdbError::SchemaError:
544 // TODO perhaps we need to do more here, invalidate also in the cache
545 m_table->setStatusInvalid();
546 /* Close other open handlers not used by any thread */
547 TABLE_LIST table_list;
548 bzero((char*) &table_list,sizeof(table_list));
549 table_list.db= m_dbname;
550 table_list.alias= table_list.table_name= m_tabname;
551 close_cached_tables(thd, &table_list, FALSE, FALSE, FALSE);
552 break;
554 default:
555 break;
557 res= ndb_to_mysql_error(&err);
558 DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
559 err.code, res));
560 if (res == HA_ERR_FOUND_DUPP_KEY)
562 char *error_data= err.details;
563 uint dupkey= MAX_KEY;
565 for (uint i= 0; i < MAX_KEY; i++)
567 if (m_index[i].type == UNIQUE_INDEX ||
568 m_index[i].type == UNIQUE_ORDERED_INDEX)
570 const NDBINDEX *unique_index=
571 (const NDBINDEX *) m_index[i].unique_index;
572 if (unique_index &&
573 (char *) unique_index->getObjectId() == error_data)
575 dupkey= i;
576 break;
580 if (m_rows_to_insert == 1)
583 We can only distinguish between primary and non-primary
584 violations here, so we need to return MAX_KEY for non-primary
585 to signal that key is unknown
587 m_dupkey= err.code == 630 ? table_share->primary_key : dupkey;
589 else
591 /* We are batching inserts, offending key is not available */
592 m_dupkey= (uint) -1;
595 DBUG_RETURN(res);
600 Override the default get_error_message in order to add the
601 error message of NDB .
604 bool ha_ndbcluster::get_error_message(int error,
605 String *buf)
607 DBUG_ENTER("ha_ndbcluster::get_error_message");
608 DBUG_PRINT("enter", ("error: %d", error));
610 Ndb *ndb= check_ndb_in_thd(current_thd);
611 if (!ndb)
612 DBUG_RETURN(FALSE);
614 const NdbError err= ndb->getNdbError(error);
615 bool temporary= err.status==NdbError::TemporaryError;
616 buf->set(err.message, strlen(err.message), &my_charset_bin);
617 DBUG_PRINT("exit", ("message: %s, temporary: %d", buf->ptr(), temporary));
618 DBUG_RETURN(temporary);
622 #ifndef DBUG_OFF
624 Check if type is supported by NDB.
627 static bool ndb_supported_type(enum_field_types type)
629 switch (type) {
630 case MYSQL_TYPE_TINY:
631 case MYSQL_TYPE_SHORT:
632 case MYSQL_TYPE_LONG:
633 case MYSQL_TYPE_INT24:
634 case MYSQL_TYPE_LONGLONG:
635 case MYSQL_TYPE_FLOAT:
636 case MYSQL_TYPE_DOUBLE:
637 case MYSQL_TYPE_DECIMAL:
638 case MYSQL_TYPE_NEWDECIMAL:
639 case MYSQL_TYPE_TIMESTAMP:
640 case MYSQL_TYPE_DATETIME:
641 case MYSQL_TYPE_DATE:
642 case MYSQL_TYPE_NEWDATE:
643 case MYSQL_TYPE_TIME:
644 case MYSQL_TYPE_YEAR:
645 case MYSQL_TYPE_STRING:
646 case MYSQL_TYPE_VAR_STRING:
647 case MYSQL_TYPE_VARCHAR:
648 case MYSQL_TYPE_TINY_BLOB:
649 case MYSQL_TYPE_BLOB:
650 case MYSQL_TYPE_MEDIUM_BLOB:
651 case MYSQL_TYPE_LONG_BLOB:
652 case MYSQL_TYPE_ENUM:
653 case MYSQL_TYPE_SET:
654 case MYSQL_TYPE_BIT:
655 case MYSQL_TYPE_GEOMETRY:
656 return TRUE;
657 case MYSQL_TYPE_NULL:
658 break;
660 return FALSE;
662 #endif /* !DBUG_OFF */
666 Check if MySQL field type forces var part in ndb storage.
668 static bool field_type_forces_var_part(enum_field_types type)
670 switch (type) {
671 case MYSQL_TYPE_VAR_STRING:
672 case MYSQL_TYPE_VARCHAR:
673 return TRUE;
674 case MYSQL_TYPE_TINY_BLOB:
675 case MYSQL_TYPE_BLOB:
676 case MYSQL_TYPE_MEDIUM_BLOB:
677 case MYSQL_TYPE_LONG_BLOB:
678 case MYSQL_TYPE_GEOMETRY:
679 return FALSE;
680 default:
681 return FALSE;
686 Instruct NDB to set the value of the hidden primary key.
689 bool ha_ndbcluster::set_hidden_key(NdbOperation *ndb_op,
690 uint fieldnr, const uchar *field_ptr)
692 DBUG_ENTER("set_hidden_key");
693 DBUG_RETURN(ndb_op->equal(fieldnr, (char*)field_ptr) != 0);
698 Instruct NDB to set the value of one primary key attribute.
701 int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field,
702 uint fieldnr, const uchar *field_ptr)
704 uint32 pack_len= field->pack_length();
705 DBUG_ENTER("set_ndb_key");
706 DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d",
707 fieldnr, field->field_name, field->type(),
708 pack_len));
709 DBUG_DUMP("key", field_ptr, pack_len);
711 DBUG_ASSERT(ndb_supported_type(field->type()));
712 DBUG_ASSERT(! (field->flags & BLOB_FLAG));
713 // Common implementation for most field types
714 DBUG_RETURN(ndb_op->equal(fieldnr, (char*) field_ptr, pack_len) != 0);
719 Instruct NDB to set the value of one attribute.
722 int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
723 uint fieldnr, int row_offset,
724 bool *set_blob_value)
726 const uchar* field_ptr= field->ptr + row_offset;
727 uint32 pack_len= field->pack_length();
728 DBUG_ENTER("set_ndb_value");
729 DBUG_PRINT("enter", ("%d: %s type: %u len=%d is_null=%s",
730 fieldnr, field->field_name, field->type(),
731 pack_len, field->is_null(row_offset) ? "Y" : "N"));
732 DBUG_DUMP("value", field_ptr, pack_len);
734 DBUG_ASSERT(ndb_supported_type(field->type()));
736 // ndb currently does not support size 0
737 uint32 empty_field;
738 if (pack_len == 0)
740 pack_len= sizeof(empty_field);
741 field_ptr= (uchar *)&empty_field;
742 if (field->is_null(row_offset))
743 empty_field= 0;
744 else
745 empty_field= 1;
747 if (! (field->flags & BLOB_FLAG))
749 if (field->type() != MYSQL_TYPE_BIT)
751 if (field->is_null(row_offset))
753 DBUG_PRINT("info", ("field is NULL"));
754 // Set value to NULL
755 DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL) != 0));
757 // Common implementation for most field types
758 DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)field_ptr) != 0);
760 else // if (field->type() == MYSQL_TYPE_BIT)
762 longlong bits= field->val_int();
764 // Round up bit field length to nearest word boundry
765 pack_len= ((pack_len + 3) >> 2) << 2;
766 DBUG_ASSERT(pack_len <= 8);
767 if (field->is_null(row_offset))
768 // Set value to NULL
769 DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL) != 0));
770 DBUG_PRINT("info", ("bit field"));
771 DBUG_DUMP("value", (uchar*)&bits, pack_len);
772 #ifdef WORDS_BIGENDIAN
773 /* store lsw first */
774 bits = ((bits >> 32) & 0x00000000FFFFFFFFLL)
775 | ((bits << 32) & 0xFFFFFFFF00000000LL);
776 #endif
777 DBUG_RETURN(ndb_op->setValue(fieldnr, (char*)&bits) != 0);
780 // Blob type
781 NdbBlob *ndb_blob= ndb_op->getBlobHandle(fieldnr);
782 if (ndb_blob != NULL)
784 if (field->is_null(row_offset))
785 DBUG_RETURN(ndb_blob->setNull() != 0);
787 Field_blob *field_blob= (Field_blob*)field;
789 // Get length and pointer to data
790 uint32 blob_len= field_blob->get_length(field_ptr);
791 uchar* blob_ptr= NULL;
792 field_blob->get_ptr(&blob_ptr);
794 // Looks like NULL ptr signals length 0 blob
795 if (blob_ptr == NULL) {
796 DBUG_ASSERT(blob_len == 0);
797 blob_ptr= (uchar*)"";
800 DBUG_PRINT("value", ("set blob ptr: 0x%lx len: %u",
801 (long) blob_ptr, blob_len));
802 DBUG_DUMP("value", blob_ptr, min(blob_len, 26));
804 if (set_blob_value)
805 *set_blob_value= TRUE;
806 // No callback needed to write value
807 DBUG_RETURN(ndb_blob->setValue(blob_ptr, blob_len) != 0);
809 DBUG_RETURN(1);
814 NdbBlob::ActiveHook g_get_ndb_blobs_value;
817 Callback to read all blob values.
818 - not done in unpack_record because unpack_record is valid
819 after execute(Commit) but reading blobs is not
820 - may only generate read operations; they have to be executed
821 somewhere before the data is available
822 - due to single buffer for all blobs, we let the last blob
823 process all blobs (last so that all are active)
824 - null bit is still set in unpack_record.
826 @todo
827 allocate blob part aligned buffers
830 int g_get_ndb_blobs_value(NdbBlob *ndb_blob, void *arg)
832 DBUG_ENTER("g_get_ndb_blobs_value");
833 if (ndb_blob->blobsNextBlob() != NULL)
834 DBUG_RETURN(0);
835 ha_ndbcluster *ha= (ha_ndbcluster *)arg;
836 int ret= get_ndb_blobs_value(ha->table, ha->m_value,
837 ha->m_blobs_buffer, ha->m_blobs_buffer_size,
838 ha->m_blobs_offset);
839 DBUG_RETURN(ret);
843 This routine is shared by injector. There is no common blobs buffer
844 so the buffer and length are passed by reference. Injector also
845 passes a record pointer diff.
847 int get_ndb_blobs_value(TABLE* table, NdbValue* value_array,
848 uchar*& buffer, uint& buffer_size,
849 my_ptrdiff_t ptrdiff)
851 DBUG_ENTER("get_ndb_blobs_value");
853 // Field has no field number so cannot use TABLE blob_field
854 // Loop twice, first only counting total buffer size
855 for (int loop= 0; loop <= 1; loop++)
857 uint32 offset= 0;
858 for (uint i= 0; i < table->s->fields; i++)
860 Field *field= table->field[i];
861 NdbValue value= value_array[i];
862 if (! (field->flags & BLOB_FLAG))
863 continue;
864 if (value.blob == NULL)
866 DBUG_PRINT("info",("[%u] skipped", i));
867 continue;
869 Field_blob *field_blob= (Field_blob *)field;
870 NdbBlob *ndb_blob= value.blob;
871 int isNull;
872 if (ndb_blob->getNull(isNull) != 0)
873 ERR_RETURN(ndb_blob->getNdbError());
874 if (isNull == 0) {
875 Uint64 len64= 0;
876 if (ndb_blob->getLength(len64) != 0)
877 ERR_RETURN(ndb_blob->getNdbError());
878 // Align to Uint64
879 uint32 size= len64;
880 if (size % 8 != 0)
881 size+= 8 - size % 8;
882 if (loop == 1)
884 uchar *buf= buffer + offset;
885 uint32 len= 0xffffffff; // Max uint32
886 if (ndb_blob->readData(buf, len) != 0)
887 ERR_RETURN(ndb_blob->getNdbError());
888 DBUG_PRINT("info", ("[%u] offset: %u buf: 0x%lx len=%u [ptrdiff=%d]",
889 i, offset, (long) buf, len, (int)ptrdiff));
890 DBUG_ASSERT(len == len64);
891 // Ugly hack assumes only ptr needs to be changed
892 field_blob->set_ptr_offset(ptrdiff, len, buf);
894 offset+= size;
896 else if (loop == 1) // undefined or null
898 // have to set length even in this case
899 uchar *buf= buffer + offset; // or maybe NULL
900 uint32 len= 0;
901 field_blob->set_ptr_offset(ptrdiff, len, buf);
902 DBUG_PRINT("info", ("[%u] isNull=%d", i, isNull));
905 if (loop == 0 && offset > buffer_size)
907 my_free(buffer, MYF(MY_ALLOW_ZERO_PTR));
908 buffer_size= 0;
909 DBUG_PRINT("info", ("allocate blobs buffer size %u", offset));
910 buffer= (uchar*) my_malloc(offset, MYF(MY_WME));
911 if (buffer == NULL)
913 sql_print_error("ha_ndbcluster::get_ndb_blobs_value: "
914 "my_malloc(%u) failed", offset);
915 DBUG_RETURN(-1);
917 buffer_size= offset;
920 DBUG_RETURN(0);
925 Instruct NDB to fetch one field.
927 Data is read directly into buffer provided by field
928 if field is NULL, data is read into memory provided by NDBAPI.
931 int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field,
932 uint fieldnr, uchar* buf)
934 DBUG_ENTER("get_ndb_value");
935 DBUG_PRINT("enter", ("fieldnr: %d flags: %o", fieldnr,
936 (int)(field != NULL ? field->flags : 0)));
938 if (field != NULL)
940 DBUG_ASSERT(buf);
941 DBUG_ASSERT(ndb_supported_type(field->type()));
942 DBUG_ASSERT(field->ptr != NULL);
943 if (! (field->flags & BLOB_FLAG))
945 if (field->type() != MYSQL_TYPE_BIT)
947 uchar *field_buf;
948 if (field->pack_length() != 0)
949 field_buf= buf + (field->ptr - table->record[0]);
950 else
951 field_buf= (uchar *)&dummy_buf;
952 m_value[fieldnr].rec= ndb_op->getValue(fieldnr,
953 (char*) field_buf);
955 else // if (field->type() == MYSQL_TYPE_BIT)
957 m_value[fieldnr].rec= ndb_op->getValue(fieldnr);
959 DBUG_RETURN(m_value[fieldnr].rec == NULL);
962 // Blob type
963 NdbBlob *ndb_blob= ndb_op->getBlobHandle(fieldnr);
964 m_value[fieldnr].blob= ndb_blob;
965 if (ndb_blob != NULL)
967 // Set callback
968 m_blobs_offset= buf - (uchar*) table->record[0];
969 void *arg= (void *)this;
970 DBUG_RETURN(ndb_blob->setActiveHook(g_get_ndb_blobs_value, arg) != 0);
972 DBUG_RETURN(1);
975 // Used for hidden key only
976 m_value[fieldnr].rec= ndb_op->getValue(fieldnr, (char*) m_ref);
977 DBUG_RETURN(m_value[fieldnr].rec == NULL);
981 Instruct NDB to fetch the partition id (fragment id)
983 int ha_ndbcluster::get_ndb_partition_id(NdbOperation *ndb_op)
985 DBUG_ENTER("get_ndb_partition_id");
986 DBUG_RETURN(ndb_op->getValue(NdbDictionary::Column::FRAGMENT,
987 (char *)&m_part_id) == NULL);
991 Check if any set or get of blob value in current query.
994 bool ha_ndbcluster::uses_blob_value()
996 MY_BITMAP *bitmap;
997 uint *blob_index, *blob_index_end;
998 if (table_share->blob_fields == 0)
999 return FALSE;
1001 bitmap= m_write_op ? table->write_set : table->read_set;
1002 blob_index= table_share->blob_field;
1003 blob_index_end= blob_index + table_share->blob_fields;
1006 if (bitmap_is_set(bitmap, table->field[*blob_index]->field_index))
1007 return TRUE;
1008 } while (++blob_index != blob_index_end);
1009 return FALSE;
1014 Get metadata for this table from NDB.
1016 Check that frm-file on disk is equal to frm-file
1017 of table accessed in NDB.
1019 @retval
1020 0 ok
1021 @retval
1022 -2 Meta data has changed; Re-read data and try again
1025 int cmp_frm(const NDBTAB *ndbtab, const void *pack_data,
1026 uint pack_length)
1028 DBUG_ENTER("cmp_frm");
1030 Compare FrmData in NDB with frm file from disk.
1032 if ((pack_length != ndbtab->getFrmLength()) ||
1033 (memcmp(pack_data, ndbtab->getFrmData(), pack_length)))
1034 DBUG_RETURN(1);
1035 DBUG_RETURN(0);
1038 int ha_ndbcluster::get_metadata(const char *path)
1040 Ndb *ndb= get_ndb();
1041 NDBDICT *dict= ndb->getDictionary();
1042 const NDBTAB *tab;
1043 int error;
1044 DBUG_ENTER("get_metadata");
1045 DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, path));
1047 DBUG_ASSERT(m_table == NULL);
1048 DBUG_ASSERT(m_table_info == NULL);
1050 uchar *data= NULL, *pack_data= NULL;
1051 size_t length, pack_length;
1054 Compare FrmData in NDB with frm file from disk.
1056 error= 0;
1057 if (readfrm(path, &data, &length) ||
1058 packfrm(data, length, &pack_data, &pack_length))
1060 my_free(data, MYF(MY_ALLOW_ZERO_PTR));
1061 my_free(pack_data, MYF(MY_ALLOW_ZERO_PTR));
1062 DBUG_RETURN(1);
1065 Ndb_table_guard ndbtab_g(dict, m_tabname);
1066 if (!(tab= ndbtab_g.get_table()))
1067 ERR_RETURN(dict->getNdbError());
1069 if (get_ndb_share_state(m_share) != NSS_ALTERED
1070 && cmp_frm(tab, pack_data, pack_length))
1072 DBUG_PRINT("error",
1073 ("metadata, pack_length: %lu getFrmLength: %d memcmp: %d",
1074 (ulong) pack_length, tab->getFrmLength(),
1075 memcmp(pack_data, tab->getFrmData(), pack_length)));
1076 DBUG_DUMP("pack_data", (uchar*) pack_data, pack_length);
1077 DBUG_DUMP("frm", (uchar*) tab->getFrmData(), tab->getFrmLength());
1078 error= HA_ERR_TABLE_DEF_CHANGED;
1080 my_free((char*)data, MYF(0));
1081 my_free((char*)pack_data, MYF(0));
1083 if (error)
1084 goto err;
1086 DBUG_PRINT("info", ("fetched table %s", tab->getName()));
1087 m_table= tab;
1088 if ((error= open_indexes(ndb, table, FALSE)) == 0)
1090 ndbtab_g.release();
1091 DBUG_RETURN(0);
1093 err:
1094 ndbtab_g.invalidate();
1095 m_table= NULL;
1096 DBUG_RETURN(error);
1099 static int fix_unique_index_attr_order(NDB_INDEX_DATA &data,
1100 const NDBINDEX *index,
1101 KEY *key_info)
1103 DBUG_ENTER("fix_unique_index_attr_order");
1104 unsigned sz= index->getNoOfIndexColumns();
1106 if (data.unique_index_attrid_map)
1107 my_free((char*)data.unique_index_attrid_map, MYF(0));
1108 data.unique_index_attrid_map= (uchar*)my_malloc(sz,MYF(MY_WME));
1109 if (data.unique_index_attrid_map == 0)
1111 sql_print_error("fix_unique_index_attr_order: my_malloc(%u) failure",
1112 (unsigned int)sz);
1113 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
1116 KEY_PART_INFO* key_part= key_info->key_part;
1117 KEY_PART_INFO* end= key_part+key_info->key_parts;
1118 DBUG_ASSERT(key_info->key_parts == sz);
1119 for (unsigned i= 0; key_part != end; key_part++, i++)
1121 const char *field_name= key_part->field->field_name;
1122 #ifndef DBUG_OFF
1123 data.unique_index_attrid_map[i]= 255;
1124 #endif
1125 for (unsigned j= 0; j < sz; j++)
1127 const NDBCOL *c= index->getColumn(j);
1128 if (strcmp(field_name, c->getName()) == 0)
1130 data.unique_index_attrid_map[i]= j;
1131 break;
1134 DBUG_ASSERT(data.unique_index_attrid_map[i] != 255);
1136 DBUG_RETURN(0);
1140 Create all the indexes for a table.
1141 If any index should fail to be created,
1142 the error is returned immediately
1144 int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab)
1146 uint i;
1147 int error= 0;
1148 const char *index_name;
1149 KEY* key_info= tab->key_info;
1150 const char **key_name= tab->s->keynames.type_names;
1151 DBUG_ENTER("ha_ndbcluster::create_indexes");
1153 for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
1155 index_name= *key_name;
1156 NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
1157 error= create_index(index_name, key_info, idx_type, i);
1158 if (error)
1160 DBUG_PRINT("error", ("Failed to create index %u", i));
1161 break;
1165 DBUG_RETURN(error);
1168 static void ndb_init_index(NDB_INDEX_DATA &data)
1170 data.type= UNDEFINED_INDEX;
1171 data.status= UNDEFINED;
1172 data.unique_index= NULL;
1173 data.index= NULL;
1174 data.unique_index_attrid_map= NULL;
1175 data.index_stat=NULL;
1176 data.index_stat_cache_entries=0;
1177 data.index_stat_update_freq=0;
1178 data.index_stat_query_count=0;
1181 static void ndb_clear_index(NDB_INDEX_DATA &data)
1183 if (data.unique_index_attrid_map)
1185 my_free((char*)data.unique_index_attrid_map, MYF(0));
1187 if (data.index_stat)
1189 delete data.index_stat;
1191 ndb_init_index(data);
1195 Associate a direct reference to an index handle
1196 with an index (for faster access)
1198 int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info,
1199 const char *index_name, uint index_no)
1201 int error= 0;
1202 NDB_INDEX_TYPE idx_type= get_index_type_from_table(index_no);
1203 m_index[index_no].type= idx_type;
1204 DBUG_ENTER("ha_ndbcluster::add_index_handle");
1205 DBUG_PRINT("enter", ("table %s", m_tabname));
1207 if (idx_type != PRIMARY_KEY_INDEX && idx_type != UNIQUE_INDEX)
1209 DBUG_PRINT("info", ("Get handle to index %s", index_name));
1210 const NDBINDEX *index;
1213 index= dict->getIndexGlobal(index_name, *m_table);
1214 if (!index)
1215 ERR_RETURN(dict->getNdbError());
1216 DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d",
1217 (long) index,
1218 index->getObjectId(),
1219 index->getObjectVersion() & 0xFFFFFF,
1220 index->getObjectVersion() >> 24,
1221 index->getObjectStatus()));
1222 DBUG_ASSERT(index->getObjectStatus() ==
1223 NdbDictionary::Object::Retrieved);
1224 break;
1225 } while (1);
1226 m_index[index_no].index= index;
1227 // ordered index - add stats
1228 NDB_INDEX_DATA& d=m_index[index_no];
1229 delete d.index_stat;
1230 d.index_stat=NULL;
1231 if (thd->variables.ndb_index_stat_enable)
1233 d.index_stat=new NdbIndexStat(index);
1234 d.index_stat_cache_entries=thd->variables.ndb_index_stat_cache_entries;
1235 d.index_stat_update_freq=thd->variables.ndb_index_stat_update_freq;
1236 d.index_stat_query_count=0;
1237 d.index_stat->alloc_cache(d.index_stat_cache_entries);
1238 DBUG_PRINT("info", ("index %s stat=on cache_entries=%u update_freq=%u",
1239 index->getName(),
1240 d.index_stat_cache_entries,
1241 d.index_stat_update_freq));
1242 } else
1244 DBUG_PRINT("info", ("index %s stat=off", index->getName()));
1247 if (idx_type == UNIQUE_ORDERED_INDEX || idx_type == UNIQUE_INDEX)
1249 char unique_index_name[FN_LEN + 1];
1250 static const char* unique_suffix= "$unique";
1251 m_has_unique_index= TRUE;
1252 strxnmov(unique_index_name, FN_LEN, index_name, unique_suffix, NullS);
1253 DBUG_PRINT("info", ("Get handle to unique_index %s", unique_index_name));
1254 const NDBINDEX *index;
1257 index= dict->getIndexGlobal(unique_index_name, *m_table);
1258 if (!index)
1259 ERR_RETURN(dict->getNdbError());
1260 DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d",
1261 (long) index,
1262 index->getObjectId(),
1263 index->getObjectVersion() & 0xFFFFFF,
1264 index->getObjectVersion() >> 24,
1265 index->getObjectStatus()));
1266 DBUG_ASSERT(index->getObjectStatus() ==
1267 NdbDictionary::Object::Retrieved);
1268 break;
1269 } while (1);
1270 m_index[index_no].unique_index= index;
1271 error= fix_unique_index_attr_order(m_index[index_no], index, key_info);
1273 if (!error)
1274 m_index[index_no].status= ACTIVE;
1276 DBUG_RETURN(error);
1280 Associate index handles for each index of a table
1282 int ha_ndbcluster::open_indexes(Ndb *ndb, TABLE *tab, bool ignore_error)
1284 uint i;
1285 int error= 0;
1286 THD *thd=current_thd;
1287 NDBDICT *dict= ndb->getDictionary();
1288 KEY* key_info= tab->key_info;
1289 const char **key_name= tab->s->keynames.type_names;
1290 DBUG_ENTER("ha_ndbcluster::open_indexes");
1291 m_has_unique_index= FALSE;
1292 for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
1294 if ((error= add_index_handle(thd, dict, key_info, *key_name, i)))
1296 if (ignore_error)
1297 m_index[i].index= m_index[i].unique_index= NULL;
1298 else
1299 break;
1301 m_index[i].null_in_unique_index= FALSE;
1302 if (check_index_fields_not_null(key_info))
1303 m_index[i].null_in_unique_index= TRUE;
1306 if (error && !ignore_error)
1308 while (i > 0)
1310 i--;
1311 if (m_index[i].index)
1313 dict->removeIndexGlobal(*m_index[i].index, 1);
1314 m_index[i].index= NULL;
1316 if (m_index[i].unique_index)
1318 dict->removeIndexGlobal(*m_index[i].unique_index, 1);
1319 m_index[i].unique_index= NULL;
1324 DBUG_ASSERT(error == 0 || error == 4243);
1326 DBUG_RETURN(error);
1330 Renumber indexes in index list by shifting out
1331 indexes that are to be dropped
1333 void ha_ndbcluster::renumber_indexes(Ndb *ndb, TABLE *tab)
1335 uint i;
1336 const char *index_name;
1337 KEY* key_info= tab->key_info;
1338 const char **key_name= tab->s->keynames.type_names;
1339 DBUG_ENTER("ha_ndbcluster::renumber_indexes");
1341 for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
1343 index_name= *key_name;
1344 NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
1345 m_index[i].type= idx_type;
1346 if (m_index[i].status == TO_BE_DROPPED)
1348 DBUG_PRINT("info", ("Shifting index %s(%i) out of the list",
1349 index_name, i));
1350 NDB_INDEX_DATA tmp;
1351 uint j= i + 1;
1352 // Shift index out of list
1353 while(j != MAX_KEY && m_index[j].status != UNDEFINED)
1355 tmp= m_index[j - 1];
1356 m_index[j - 1]= m_index[j];
1357 m_index[j]= tmp;
1358 j++;
1363 DBUG_VOID_RETURN;
1367 Drop all indexes that are marked for deletion
1369 int ha_ndbcluster::drop_indexes(Ndb *ndb, TABLE *tab)
1371 uint i;
1372 int error= 0;
1373 const char *index_name;
1374 KEY* key_info= tab->key_info;
1375 NDBDICT *dict= ndb->getDictionary();
1376 DBUG_ENTER("ha_ndbcluster::drop_indexes");
1378 for (i= 0; i < tab->s->keys; i++, key_info++)
1380 NDB_INDEX_TYPE idx_type= get_index_type_from_table(i);
1381 m_index[i].type= idx_type;
1382 if (m_index[i].status == TO_BE_DROPPED)
1384 const NdbDictionary::Index *index= m_index[i].index;
1385 const NdbDictionary::Index *unique_index= m_index[i].unique_index;
1387 if (index)
1389 index_name= index->getName();
1390 DBUG_PRINT("info", ("Dropping index %u: %s", i, index_name));
1391 // Drop ordered index from ndb
1392 error= dict->dropIndexGlobal(*index);
1393 if (!error)
1395 dict->removeIndexGlobal(*index, 1);
1396 m_index[i].index= NULL;
1399 if (!error && unique_index)
1401 index_name= unique_index->getName();
1402 DBUG_PRINT("info", ("Dropping unique index %u: %s", i, index_name));
1403 // Drop unique index from ndb
1404 error= dict->dropIndexGlobal(*unique_index);
1405 if (!error)
1407 dict->removeIndexGlobal(*unique_index, 1);
1408 m_index[i].unique_index= NULL;
1411 if (error)
1412 DBUG_RETURN(error);
1413 ndb_clear_index(m_index[i]);
1414 continue;
1418 DBUG_RETURN(error);
1422 Decode the type of an index from information
1423 provided in table object.
1425 NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_table(uint inx) const
1427 return get_index_type_from_key(inx, table_share->key_info,
1428 inx == table_share->primary_key);
1431 NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_key(uint inx,
1432 KEY *key_info,
1433 bool primary) const
1435 bool is_hash_index= (key_info[inx].algorithm ==
1436 HA_KEY_ALG_HASH);
1437 if (primary)
1438 return is_hash_index ? PRIMARY_KEY_INDEX : PRIMARY_KEY_ORDERED_INDEX;
1440 return ((key_info[inx].flags & HA_NOSAME) ?
1441 (is_hash_index ? UNIQUE_INDEX : UNIQUE_ORDERED_INDEX) :
1442 ORDERED_INDEX);
1445 bool ha_ndbcluster::check_index_fields_not_null(KEY* key_info)
1447 KEY_PART_INFO* key_part= key_info->key_part;
1448 KEY_PART_INFO* end= key_part+key_info->key_parts;
1449 DBUG_ENTER("ha_ndbcluster::check_index_fields_not_null");
1451 for (; key_part != end; key_part++)
1453 Field* field= key_part->field;
1454 if (field->maybe_null())
1455 DBUG_RETURN(TRUE);
1458 DBUG_RETURN(FALSE);
1461 void ha_ndbcluster::release_metadata(THD *thd, Ndb *ndb)
1463 uint i;
1465 DBUG_ENTER("release_metadata");
1466 DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
1468 NDBDICT *dict= ndb->getDictionary();
1469 int invalidate_indexes= 0;
1470 if (thd && thd->lex && thd->lex->sql_command == SQLCOM_FLUSH)
1472 invalidate_indexes = 1;
1474 if (m_table != NULL)
1476 if (m_table->getObjectStatus() == NdbDictionary::Object::Invalid)
1477 invalidate_indexes= 1;
1478 dict->removeTableGlobal(*m_table, invalidate_indexes);
1480 // TODO investigate
1481 DBUG_ASSERT(m_table_info == NULL);
1482 m_table_info= NULL;
1484 // Release index list
1485 for (i= 0; i < MAX_KEY; i++)
1487 if (m_index[i].unique_index)
1489 DBUG_ASSERT(m_table != NULL);
1490 dict->removeIndexGlobal(*m_index[i].unique_index, invalidate_indexes);
1492 if (m_index[i].index)
1494 DBUG_ASSERT(m_table != NULL);
1495 dict->removeIndexGlobal(*m_index[i].index, invalidate_indexes);
1497 ndb_clear_index(m_index[i]);
1500 m_table= NULL;
1501 DBUG_VOID_RETURN;
1504 int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type)
1506 if (type >= TL_WRITE_ALLOW_WRITE)
1507 return NdbOperation::LM_Exclusive;
1508 if (type == TL_READ_WITH_SHARED_LOCKS ||
1509 uses_blob_value())
1510 return NdbOperation::LM_Read;
1511 return NdbOperation::LM_CommittedRead;
1514 static const ulong index_type_flags[]=
1516 /* UNDEFINED_INDEX */
1519 /* PRIMARY_KEY_INDEX */
1520 HA_ONLY_WHOLE_INDEX,
1522 /* PRIMARY_KEY_ORDERED_INDEX */
1524 Enable HA_KEYREAD_ONLY when "sorted" indexes are supported,
1525 thus ORDERD BY clauses can be optimized by reading directly
1526 through the index.
1528 // HA_KEYREAD_ONLY |
1529 HA_READ_NEXT |
1530 HA_READ_PREV |
1531 HA_READ_RANGE |
1532 HA_READ_ORDER,
1534 /* UNIQUE_INDEX */
1535 HA_ONLY_WHOLE_INDEX,
1537 /* UNIQUE_ORDERED_INDEX */
1538 HA_READ_NEXT |
1539 HA_READ_PREV |
1540 HA_READ_RANGE |
1541 HA_READ_ORDER,
1543 /* ORDERED_INDEX */
1544 HA_READ_NEXT |
1545 HA_READ_PREV |
1546 HA_READ_RANGE |
1547 HA_READ_ORDER
1550 static const int index_flags_size= sizeof(index_type_flags)/sizeof(ulong);
1552 inline NDB_INDEX_TYPE ha_ndbcluster::get_index_type(uint idx_no) const
1554 DBUG_ASSERT(idx_no < MAX_KEY);
1555 return m_index[idx_no].type;
1558 inline bool ha_ndbcluster::has_null_in_unique_index(uint idx_no) const
1560 DBUG_ASSERT(idx_no < MAX_KEY);
1561 return m_index[idx_no].null_in_unique_index;
1566 Get the flags for an index.
1568 @return
1569 flags depending on the type of the index.
1572 inline ulong ha_ndbcluster::index_flags(uint idx_no, uint part,
1573 bool all_parts) const
1575 DBUG_ENTER("ha_ndbcluster::index_flags");
1576 DBUG_PRINT("enter", ("idx_no: %u", idx_no));
1577 DBUG_ASSERT(get_index_type_from_table(idx_no) < index_flags_size);
1578 DBUG_RETURN(index_type_flags[get_index_type_from_table(idx_no)] |
1579 HA_KEY_SCAN_NOT_ROR);
1582 static void shrink_varchar(Field* field, const uchar* & ptr, uchar* buf)
1584 if (field->type() == MYSQL_TYPE_VARCHAR && ptr != NULL) {
1585 Field_varstring* f= (Field_varstring*)field;
1586 if (f->length_bytes == 1) {
1587 uint pack_len= field->pack_length();
1588 DBUG_ASSERT(1 <= pack_len && pack_len <= 256);
1589 if (ptr[1] == 0) {
1590 buf[0]= ptr[0];
1591 } else {
1592 DBUG_ASSERT(FALSE);
1593 buf[0]= 255;
1595 memmove(buf + 1, ptr + 2, pack_len - 1);
1596 ptr= buf;
1601 int ha_ndbcluster::set_primary_key(NdbOperation *op, const uchar *key)
1603 KEY* key_info= table->key_info + table_share->primary_key;
1604 KEY_PART_INFO* key_part= key_info->key_part;
1605 KEY_PART_INFO* end= key_part+key_info->key_parts;
1606 DBUG_ENTER("set_primary_key");
1608 for (; key_part != end; key_part++)
1610 Field* field= key_part->field;
1611 const uchar* ptr= key;
1612 uchar buf[256];
1613 shrink_varchar(field, ptr, buf);
1614 if (set_ndb_key(op, field,
1615 key_part->fieldnr-1, ptr))
1616 ERR_RETURN(op->getNdbError());
1617 key += key_part->store_length;
1619 DBUG_RETURN(0);
1623 int ha_ndbcluster::set_primary_key_from_record(NdbOperation *op, const uchar *record)
1625 KEY* key_info= table->key_info + table_share->primary_key;
1626 KEY_PART_INFO* key_part= key_info->key_part;
1627 KEY_PART_INFO* end= key_part+key_info->key_parts;
1628 DBUG_ENTER("set_primary_key_from_record");
1630 for (; key_part != end; key_part++)
1632 Field* field= key_part->field;
1633 if (set_ndb_key(op, field,
1634 key_part->fieldnr-1, record+key_part->offset))
1635 ERR_RETURN(op->getNdbError());
1637 DBUG_RETURN(0);
1640 bool ha_ndbcluster::check_index_fields_in_write_set(uint keyno)
1642 KEY* key_info= table->key_info + keyno;
1643 KEY_PART_INFO* key_part= key_info->key_part;
1644 KEY_PART_INFO* end= key_part+key_info->key_parts;
1645 uint i;
1646 DBUG_ENTER("check_index_fields_in_write_set");
1648 for (i= 0; key_part != end; key_part++, i++)
1650 Field* field= key_part->field;
1651 if (!bitmap_is_set(table->write_set, field->field_index))
1653 DBUG_RETURN(false);
1657 DBUG_RETURN(true);
1660 int ha_ndbcluster::set_index_key_from_record(NdbOperation *op,
1661 const uchar *record, uint keyno)
1663 KEY* key_info= table->key_info + keyno;
1664 KEY_PART_INFO* key_part= key_info->key_part;
1665 KEY_PART_INFO* end= key_part+key_info->key_parts;
1666 uint i;
1667 DBUG_ENTER("set_index_key_from_record");
1669 for (i= 0; key_part != end; key_part++, i++)
1671 Field* field= key_part->field;
1672 if (set_ndb_key(op, field, m_index[keyno].unique_index_attrid_map[i],
1673 record+key_part->offset))
1674 ERR_RETURN(m_active_trans->getNdbError());
1676 DBUG_RETURN(0);
1679 int
1680 ha_ndbcluster::set_index_key(NdbOperation *op,
1681 const KEY *key_info,
1682 const uchar * key_ptr)
1684 DBUG_ENTER("ha_ndbcluster::set_index_key");
1685 uint i;
1686 KEY_PART_INFO* key_part= key_info->key_part;
1687 KEY_PART_INFO* end= key_part+key_info->key_parts;
1689 for (i= 0; key_part != end; key_part++, i++)
1691 Field* field= key_part->field;
1692 const uchar* ptr= key_part->null_bit ? key_ptr + 1 : key_ptr;
1693 uchar buf[256];
1694 shrink_varchar(field, ptr, buf);
1695 if (set_ndb_key(op, field, m_index[active_index].unique_index_attrid_map[i], ptr))
1696 ERR_RETURN(m_active_trans->getNdbError());
1697 key_ptr+= key_part->store_length;
1699 DBUG_RETURN(0);
1702 inline
1703 int ha_ndbcluster::define_read_attrs(uchar* buf, NdbOperation* op)
1705 uint i;
1706 DBUG_ENTER("define_read_attrs");
1708 // Define attributes to read
1709 for (i= 0; i < table_share->fields; i++)
1711 Field *field= table->field[i];
1712 if (bitmap_is_set(table->read_set, i) ||
1713 ((field->flags & PRI_KEY_FLAG)))
1715 if (get_ndb_value(op, field, i, buf))
1716 ERR_RETURN(op->getNdbError());
1718 else
1720 m_value[i].ptr= NULL;
1724 if (table_share->primary_key == MAX_KEY)
1726 DBUG_PRINT("info", ("Getting hidden key"));
1727 // Scanning table with no primary key
1728 int hidden_no= table_share->fields;
1729 #ifndef DBUG_OFF
1730 const NDBTAB *tab= (const NDBTAB *) m_table;
1731 if (!tab->getColumn(hidden_no))
1732 DBUG_RETURN(1);
1733 #endif
1734 if (get_ndb_value(op, NULL, hidden_no, NULL))
1735 ERR_RETURN(op->getNdbError());
1737 DBUG_RETURN(0);
1742 Read one record from NDB using primary key.
1745 int ha_ndbcluster::pk_read(const uchar *key, uint key_len, uchar *buf,
1746 uint32 part_id)
1748 uint no_fields= table_share->fields;
1749 NdbConnection *trans= m_active_trans;
1750 NdbOperation *op;
1752 int res;
1753 DBUG_ENTER("pk_read");
1754 DBUG_PRINT("enter", ("key_len: %u", key_len));
1755 DBUG_DUMP("key", key, key_len);
1756 m_write_op= FALSE;
1758 NdbOperation::LockMode lm=
1759 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
1760 if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
1761 op->readTuple(lm) != 0)
1762 ERR_RETURN(trans->getNdbError());
1764 if (table_share->primary_key == MAX_KEY)
1766 // This table has no primary key, use "hidden" primary key
1767 DBUG_PRINT("info", ("Using hidden key"));
1768 DBUG_DUMP("key", key, 8);
1769 if (set_hidden_key(op, no_fields, key))
1770 ERR_RETURN(trans->getNdbError());
1772 // Read key at the same time, for future reference
1773 if (get_ndb_value(op, NULL, no_fields, NULL))
1774 ERR_RETURN(trans->getNdbError());
1776 else
1778 if ((res= set_primary_key(op, key)))
1779 return res;
1782 if ((res= define_read_attrs(buf, op)))
1783 DBUG_RETURN(res);
1785 if (m_use_partition_function)
1787 op->setPartitionId(part_id);
1788 // If table has user defined partitioning
1789 // and no indexes, we need to read the partition id
1790 // to support ORDER BY queries
1791 if (table_share->primary_key == MAX_KEY &&
1792 get_ndb_partition_id(op))
1793 ERR_RETURN(trans->getNdbError());
1796 if ((res = execute_no_commit_ie(this,trans,FALSE)) != 0 ||
1797 op->getNdbError().code)
1799 table->status= STATUS_NOT_FOUND;
1800 DBUG_RETURN(ndb_err(trans));
1803 // The value have now been fetched from NDB
1804 unpack_record(buf);
1805 table->status= 0;
1806 DBUG_RETURN(0);
1810 Read one complementing record from NDB using primary key from old_data
1811 or hidden key.
1814 int ha_ndbcluster::complemented_read(const uchar *old_data, uchar *new_data,
1815 uint32 old_part_id)
1817 uint no_fields= table_share->fields, i;
1818 NdbTransaction *trans= m_active_trans;
1819 NdbOperation *op;
1820 DBUG_ENTER("complemented_read");
1821 m_write_op= FALSE;
1823 if (bitmap_is_set_all(table->read_set))
1825 // We have allready retrieved all fields, nothing to complement
1826 DBUG_RETURN(0);
1829 NdbOperation::LockMode lm=
1830 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
1831 if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
1832 op->readTuple(lm) != 0)
1833 ERR_RETURN(trans->getNdbError());
1834 if (table_share->primary_key != MAX_KEY)
1836 if (set_primary_key_from_record(op, old_data))
1837 ERR_RETURN(trans->getNdbError());
1839 else
1841 // This table has no primary key, use "hidden" primary key
1842 if (set_hidden_key(op, table->s->fields, m_ref))
1843 ERR_RETURN(op->getNdbError());
1846 if (m_use_partition_function)
1847 op->setPartitionId(old_part_id);
1849 // Read all unreferenced non-key field(s)
1850 for (i= 0; i < no_fields; i++)
1852 Field *field= table->field[i];
1853 if (!((field->flags & PRI_KEY_FLAG) ||
1854 bitmap_is_set(table->read_set, i)) &&
1855 !bitmap_is_set(table->write_set, i))
1857 if (get_ndb_value(op, field, i, new_data))
1858 ERR_RETURN(trans->getNdbError());
1862 if (execute_no_commit(this,trans,FALSE) != 0)
1864 table->status= STATUS_NOT_FOUND;
1865 DBUG_RETURN(ndb_err(trans));
1868 // The value have now been fetched from NDB
1869 unpack_record(new_data);
1870 table->status= 0;
1873 * restore m_value
1875 for (i= 0; i < no_fields; i++)
1877 Field *field= table->field[i];
1878 if (!((field->flags & PRI_KEY_FLAG) ||
1879 bitmap_is_set(table->read_set, i)))
1881 m_value[i].ptr= NULL;
1885 DBUG_RETURN(0);
1889 Check that all operations between first and last all
1890 have gotten the errcode
1891 If checking for HA_ERR_KEY_NOT_FOUND then update m_dupkey
1892 for all succeeding operations
1894 bool ha_ndbcluster::check_all_operations_for_error(NdbTransaction *trans,
1895 const NdbOperation *first,
1896 const NdbOperation *last,
1897 uint errcode)
1899 const NdbOperation *op= first;
1900 DBUG_ENTER("ha_ndbcluster::check_all_operations_for_error");
1902 while(op)
1904 NdbError err= op->getNdbError();
1905 if (err.status != NdbError::Success)
1907 if (ndb_to_mysql_error(&err) != (int) errcode)
1908 DBUG_RETURN(FALSE);
1909 if (op == last) break;
1910 op= trans->getNextCompletedOperation(op);
1912 else
1914 // We found a duplicate
1915 if (op->getType() == NdbOperation::UniqueIndexAccess)
1917 if (errcode == HA_ERR_KEY_NOT_FOUND)
1919 NdbIndexOperation *iop= (NdbIndexOperation *) op;
1920 const NDBINDEX *index= iop->getIndex();
1921 // Find the key_no of the index
1922 for(uint i= 0; i<table->s->keys; i++)
1924 if (m_index[i].unique_index == index)
1926 m_dupkey= i;
1927 break;
1932 else
1934 // Must have been primary key access
1935 DBUG_ASSERT(op->getType() == NdbOperation::PrimaryKeyAccess);
1936 if (errcode == HA_ERR_KEY_NOT_FOUND)
1937 m_dupkey= table->s->primary_key;
1939 DBUG_RETURN(FALSE);
1942 DBUG_RETURN(TRUE);
1947 * Check if record contains any null valued columns that are part of a key
1949 static
1951 check_null_in_record(const KEY* key_info, const uchar *record)
1953 KEY_PART_INFO *curr_part, *end_part;
1954 curr_part= key_info->key_part;
1955 end_part= curr_part + key_info->key_parts;
1957 while (curr_part != end_part)
1959 if (curr_part->null_bit &&
1960 (record[curr_part->null_offset] & curr_part->null_bit))
1961 return 1;
1962 curr_part++;
1964 return 0;
1966 We could instead pre-compute a bitmask in table_share with one bit for
1967 every null-bit in the key, and so check this just by OR'ing the bitmask
1968 with the null bitmap in the record.
1969 But not sure it's worth it.
1974 Peek to check if any rows already exist with conflicting
1975 primary key or unique index values
1978 int ha_ndbcluster::peek_indexed_rows(const uchar *record,
1979 NDB_WRITE_OP write_op)
1981 NdbTransaction *trans= m_active_trans;
1982 NdbOperation *op;
1983 const NdbOperation *first, *last;
1984 uint i;
1985 int res;
1986 DBUG_ENTER("peek_indexed_rows");
1988 NdbOperation::LockMode lm=
1989 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
1990 first= NULL;
1991 if (write_op != NDB_UPDATE && table->s->primary_key != MAX_KEY)
1994 * Fetch any row with colliding primary key
1996 if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) ||
1997 op->readTuple(lm) != 0)
1998 ERR_RETURN(trans->getNdbError());
2000 first= op;
2001 if ((res= set_primary_key_from_record(op, record)))
2002 ERR_RETURN(trans->getNdbError());
2004 if (m_use_partition_function)
2006 uint32 part_id;
2007 int error;
2008 longlong func_value;
2009 my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
2010 error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
2011 dbug_tmp_restore_column_map(table->read_set, old_map);
2012 if (error)
2014 m_part_info->err_value= func_value;
2015 DBUG_RETURN(error);
2017 op->setPartitionId(part_id);
2021 * Fetch any rows with colliding unique indexes
2023 KEY* key_info;
2024 KEY_PART_INFO *key_part, *end;
2025 for (i= 0, key_info= table->key_info; i < table->s->keys; i++, key_info++)
2027 if (i != table->s->primary_key &&
2028 key_info->flags & HA_NOSAME)
2031 A unique index is defined on table.
2032 We cannot look up a NULL field value in a unique index. But since
2033 keys with NULLs are not indexed, such rows cannot conflict anyway, so
2034 we just skip the index in this case.
2036 if (check_null_in_record(key_info, record))
2038 DBUG_PRINT("info", ("skipping check for key with NULL"));
2039 continue;
2041 if (write_op != NDB_INSERT && !check_index_fields_in_write_set(i))
2043 DBUG_PRINT("info", ("skipping check for key %u not in write_set", i));
2044 continue;
2046 NdbIndexOperation *iop;
2047 const NDBINDEX *unique_index = m_index[i].unique_index;
2048 key_part= key_info->key_part;
2049 end= key_part + key_info->key_parts;
2050 if (!(iop= trans->getNdbIndexOperation(unique_index, m_table)) ||
2051 iop->readTuple(lm) != 0)
2052 ERR_RETURN(trans->getNdbError());
2054 if (!first)
2055 first= iop;
2056 if ((res= set_index_key_from_record(iop, record, i)))
2057 ERR_RETURN(trans->getNdbError());
2060 last= trans->getLastDefinedOperation();
2061 if (first)
2062 res= execute_no_commit_ie(this,trans,FALSE);
2063 else
2065 // Table has no keys
2066 table->status= STATUS_NOT_FOUND;
2067 DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
2069 if (check_all_operations_for_error(trans, first, last,
2070 HA_ERR_KEY_NOT_FOUND))
2072 table->status= STATUS_NOT_FOUND;
2073 DBUG_RETURN(ndb_err(trans));
2075 else
2077 DBUG_PRINT("info", ("m_dupkey %d", m_dupkey));
2079 DBUG_RETURN(0);
2084 Read one record from NDB using unique secondary index.
2087 int ha_ndbcluster::unique_index_read(const uchar *key,
2088 uint key_len, uchar *buf)
2090 int res;
2091 NdbTransaction *trans= m_active_trans;
2092 NdbIndexOperation *op;
2093 DBUG_ENTER("ha_ndbcluster::unique_index_read");
2094 DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index));
2095 DBUG_DUMP("key", key, key_len);
2097 NdbOperation::LockMode lm=
2098 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
2099 if (!(op= trans->getNdbIndexOperation(m_index[active_index].unique_index,
2100 m_table)) ||
2101 op->readTuple(lm) != 0)
2102 ERR_RETURN(trans->getNdbError());
2104 // Set secondary index key(s)
2105 if ((res= set_index_key(op, table->key_info + active_index, key)))
2106 DBUG_RETURN(res);
2108 if ((res= define_read_attrs(buf, op)))
2109 DBUG_RETURN(res);
2111 if (execute_no_commit_ie(this,trans,FALSE) != 0 ||
2112 op->getNdbError().code)
2114 int err= ndb_err(trans);
2115 if(err==HA_ERR_KEY_NOT_FOUND)
2116 table->status= STATUS_NOT_FOUND;
2117 else
2118 table->status= STATUS_GARBAGE;
2120 DBUG_RETURN(err);
2123 // The value have now been fetched from NDB
2124 unpack_record(buf);
2125 table->status= 0;
2126 DBUG_RETURN(0);
2129 inline int ha_ndbcluster::fetch_next(NdbScanOperation* cursor)
2131 DBUG_ENTER("fetch_next");
2132 int local_check;
2133 NdbTransaction *trans= m_active_trans;
2135 if (m_lock_tuple)
2138 Lock level m_lock.type either TL_WRITE_ALLOW_WRITE
2139 (SELECT FOR UPDATE) or TL_READ_WITH_SHARED_LOCKS (SELECT
2140 LOCK WITH SHARE MODE) and row was not explictly unlocked
2141 with unlock_row() call
2143 NdbConnection *con_trans= m_active_trans;
2144 NdbOperation *op;
2145 // Lock row
2146 DBUG_PRINT("info", ("Keeping lock on scanned row"));
2148 if (!(op= m_active_cursor->lockCurrentTuple()))
2150 /* purecov: begin inspected */
2151 m_lock_tuple= FALSE;
2152 ERR_RETURN(con_trans->getNdbError());
2153 /* purecov: end */
2155 m_ops_pending++;
2157 m_lock_tuple= FALSE;
2159 bool contact_ndb= m_lock.type < TL_WRITE_ALLOW_WRITE &&
2160 m_lock.type != TL_READ_WITH_SHARED_LOCKS;;
2161 do {
2162 DBUG_PRINT("info", ("Call nextResult, contact_ndb: %d", contact_ndb));
2164 We can only handle one tuple with blobs at a time.
2166 if (m_ops_pending && m_blobs_pending)
2168 if (execute_no_commit(this,trans,FALSE) != 0)
2169 DBUG_RETURN(ndb_err(trans));
2170 m_ops_pending= 0;
2171 m_blobs_pending= FALSE;
2174 if ((local_check= cursor->nextResult(contact_ndb, m_force_send)) == 0)
2177 Explicitly lock tuple if "select for update" or
2178 "select lock in share mode"
2180 m_lock_tuple= (m_lock.type == TL_WRITE_ALLOW_WRITE
2182 m_lock.type == TL_READ_WITH_SHARED_LOCKS);
2183 DBUG_RETURN(0);
2185 else if (local_check == 1 || local_check == 2)
2187 // 1: No more records
2188 // 2: No more cached records
2191 Before fetching more rows and releasing lock(s),
2192 all pending update or delete operations should
2193 be sent to NDB
2195 DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending));
2196 if (m_ops_pending)
2198 if (m_transaction_on)
2200 if (execute_no_commit(this,trans,FALSE) != 0)
2201 DBUG_RETURN(-1);
2203 else
2205 if (execute_commit(this,trans) != 0)
2206 DBUG_RETURN(-1);
2207 if (trans->restart() != 0)
2209 DBUG_ASSERT(0);
2210 DBUG_RETURN(-1);
2213 m_ops_pending= 0;
2215 contact_ndb= (local_check == 2);
2217 else
2219 DBUG_RETURN(-1);
2221 } while (local_check == 2);
2223 DBUG_RETURN(1);
2227 Get the next record of a started scan. Try to fetch
2228 it locally from NdbApi cached records if possible,
2229 otherwise ask NDB for more.
2231 @note
2232 If this is a update/delete make sure to not contact
2233 NDB before any pending ops have been sent to NDB.
2236 inline int ha_ndbcluster::next_result(uchar *buf)
2238 int res;
2239 DBUG_ENTER("next_result");
2241 if (!m_active_cursor)
2242 DBUG_RETURN(HA_ERR_END_OF_FILE);
2244 if ((res= fetch_next(m_active_cursor)) == 0)
2246 DBUG_PRINT("info", ("One more record found"));
2248 unpack_record(buf);
2249 table->status= 0;
2250 DBUG_RETURN(0);
2252 else if (res == 1)
2254 // No more records
2255 table->status= STATUS_NOT_FOUND;
2257 DBUG_PRINT("info", ("No more records"));
2258 DBUG_RETURN(HA_ERR_END_OF_FILE);
2260 else
2262 DBUG_RETURN(ndb_err(m_active_trans));
2267 Set bounds for ordered index scan.
2270 int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op,
2271 uint inx,
2272 bool rir,
2273 const key_range *keys[2],
2274 uint range_no)
2276 const KEY *const key_info= table->key_info + inx;
2277 const uint key_parts= key_info->key_parts;
2278 uint key_tot_len[2];
2279 uint tot_len;
2280 uint i, j;
2282 DBUG_ENTER("set_bounds");
2283 DBUG_PRINT("info", ("key_parts=%d", key_parts));
2285 for (j= 0; j <= 1; j++)
2287 const key_range *key= keys[j];
2288 if (key != NULL)
2290 // for key->flag see ha_rkey_function
2291 DBUG_PRINT("info", ("key %d length=%d flag=%d",
2292 j, key->length, key->flag));
2293 key_tot_len[j]= key->length;
2295 else
2297 DBUG_PRINT("info", ("key %d not present", j));
2298 key_tot_len[j]= 0;
2301 tot_len= 0;
2303 for (i= 0; i < key_parts; i++)
2305 KEY_PART_INFO *key_part= &key_info->key_part[i];
2306 Field *field= key_part->field;
2307 #ifndef DBUG_OFF
2308 uint part_len= key_part->length;
2309 #endif
2310 uint part_store_len= key_part->store_length;
2311 // Info about each key part
2312 struct part_st {
2313 bool part_last;
2314 const key_range *key;
2315 const uchar *part_ptr;
2316 bool part_null;
2317 int bound_type;
2318 const uchar* bound_ptr;
2320 struct part_st part[2];
2322 for (j= 0; j <= 1; j++)
2324 struct part_st &p= part[j];
2325 p.key= NULL;
2326 p.bound_type= -1;
2327 if (tot_len < key_tot_len[j])
2329 p.part_last= (tot_len + part_store_len >= key_tot_len[j]);
2330 p.key= keys[j];
2331 p.part_ptr= &p.key->key[tot_len];
2332 p.part_null= key_part->null_bit && *p.part_ptr;
2333 p.bound_ptr= (const char *)
2334 p.part_null ? 0 : key_part->null_bit ? p.part_ptr + 1 : p.part_ptr;
2336 if (j == 0)
2338 switch (p.key->flag)
2340 case HA_READ_KEY_EXACT:
2341 if (! rir)
2342 p.bound_type= NdbIndexScanOperation::BoundEQ;
2343 else // differs for records_in_range
2344 p.bound_type= NdbIndexScanOperation::BoundLE;
2345 break;
2346 // ascending
2347 case HA_READ_KEY_OR_NEXT:
2348 p.bound_type= NdbIndexScanOperation::BoundLE;
2349 break;
2350 case HA_READ_AFTER_KEY:
2351 if (! p.part_last)
2352 p.bound_type= NdbIndexScanOperation::BoundLE;
2353 else
2354 p.bound_type= NdbIndexScanOperation::BoundLT;
2355 break;
2356 // descending
2357 case HA_READ_PREFIX_LAST: // weird
2358 p.bound_type= NdbIndexScanOperation::BoundEQ;
2359 break;
2360 case HA_READ_PREFIX_LAST_OR_PREV: // weird
2361 p.bound_type= NdbIndexScanOperation::BoundGE;
2362 break;
2363 case HA_READ_BEFORE_KEY:
2364 if (! p.part_last)
2365 p.bound_type= NdbIndexScanOperation::BoundGE;
2366 else
2367 p.bound_type= NdbIndexScanOperation::BoundGT;
2368 break;
2369 default:
2370 break;
2373 if (j == 1) {
2374 switch (p.key->flag)
2376 // ascending
2377 case HA_READ_BEFORE_KEY:
2378 if (! p.part_last)
2379 p.bound_type= NdbIndexScanOperation::BoundGE;
2380 else
2381 p.bound_type= NdbIndexScanOperation::BoundGT;
2382 break;
2383 case HA_READ_AFTER_KEY: // weird
2384 p.bound_type= NdbIndexScanOperation::BoundGE;
2385 break;
2386 default:
2387 break;
2388 // descending strangely sets no end key
2392 if (p.bound_type == -1)
2394 DBUG_PRINT("error", ("key %d unknown flag %d", j, p.key->flag));
2395 DBUG_ASSERT(FALSE);
2396 // Stop setting bounds but continue with what we have
2397 DBUG_RETURN(op->end_of_bound(range_no));
2402 // Seen with e.g. b = 1 and c > 1
2403 if (part[0].bound_type == NdbIndexScanOperation::BoundLE &&
2404 part[1].bound_type == NdbIndexScanOperation::BoundGE &&
2405 memcmp(part[0].part_ptr, part[1].part_ptr, part_store_len) == 0)
2407 DBUG_PRINT("info", ("replace LE/GE pair by EQ"));
2408 part[0].bound_type= NdbIndexScanOperation::BoundEQ;
2409 part[1].bound_type= -1;
2411 // Not seen but was in previous version
2412 if (part[0].bound_type == NdbIndexScanOperation::BoundEQ &&
2413 part[1].bound_type == NdbIndexScanOperation::BoundGE &&
2414 memcmp(part[0].part_ptr, part[1].part_ptr, part_store_len) == 0)
2416 DBUG_PRINT("info", ("remove GE from EQ/GE pair"));
2417 part[1].bound_type= -1;
2420 for (j= 0; j <= 1; j++)
2422 struct part_st &p= part[j];
2423 // Set bound if not done with this key
2424 if (p.key != NULL)
2426 DBUG_PRINT("info", ("key %d:%d offset: %d length: %d last: %d bound: %d",
2427 j, i, tot_len, part_len, p.part_last, p.bound_type));
2428 DBUG_DUMP("info", p.part_ptr, part_store_len);
2430 // Set bound if not cancelled via type -1
2431 if (p.bound_type != -1)
2433 const uchar* ptr= p.bound_ptr;
2434 uchar buf[256];
2435 shrink_varchar(field, ptr, buf);
2436 if (op->setBound(i, p.bound_type, ptr))
2437 ERR_RETURN(op->getNdbError());
2442 tot_len+= part_store_len;
2444 DBUG_RETURN(op->end_of_bound(range_no));
2448 Start ordered index scan in NDB.
2451 int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
2452 const key_range *end_key,
2453 bool sorted, bool descending,
2454 uchar* buf, part_id_range *part_spec)
2456 int res;
2457 bool restart;
2458 NdbTransaction *trans= m_active_trans;
2459 NdbIndexScanOperation *op;
2461 DBUG_ENTER("ha_ndbcluster::ordered_index_scan");
2462 DBUG_PRINT("enter", ("index: %u, sorted: %d, descending: %d",
2463 active_index, sorted, descending));
2464 DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname));
2465 m_write_op= FALSE;
2467 // Check that sorted seems to be initialised
2468 DBUG_ASSERT(sorted == 0 || sorted == 1);
2470 if (m_active_cursor == 0)
2472 restart= FALSE;
2473 NdbOperation::LockMode lm=
2474 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
2475 bool need_pk = (lm == NdbOperation::LM_Read);
2476 if (!(op= trans->getNdbIndexScanOperation(m_index[active_index].index,
2477 m_table)) ||
2478 op->readTuples(lm, 0, parallelism, sorted, descending, FALSE, need_pk))
2479 ERR_RETURN(trans->getNdbError());
2480 if (m_use_partition_function && part_spec != NULL &&
2481 part_spec->start_part == part_spec->end_part)
2482 op->setPartitionId(part_spec->start_part);
2483 m_active_cursor= op;
2484 } else {
2485 restart= TRUE;
2486 op= (NdbIndexScanOperation*)m_active_cursor;
2488 if (m_use_partition_function && part_spec != NULL &&
2489 part_spec->start_part == part_spec->end_part)
2490 op->setPartitionId(part_spec->start_part);
2491 DBUG_ASSERT(op->getSorted() == sorted);
2492 DBUG_ASSERT(op->getLockMode() ==
2493 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
2494 if (op->reset_bounds(m_force_send))
2495 DBUG_RETURN(ndb_err(m_active_trans));
2499 const key_range *keys[2]= { start_key, end_key };
2500 res= set_bounds(op, active_index, FALSE, keys);
2501 if (res)
2502 DBUG_RETURN(res);
2505 if (!restart)
2507 if (m_cond && m_cond->generate_scan_filter(op))
2508 DBUG_RETURN(ndb_err(trans));
2510 if ((res= define_read_attrs(buf, op)))
2512 DBUG_RETURN(res);
2515 // If table has user defined partitioning
2516 // and no primary key, we need to read the partition id
2517 // to support ORDER BY queries
2518 if (m_use_partition_function &&
2519 (table_share->primary_key == MAX_KEY) &&
2520 (get_ndb_partition_id(op)))
2521 ERR_RETURN(trans->getNdbError());
2524 if (execute_no_commit(this,trans,FALSE) != 0)
2525 DBUG_RETURN(ndb_err(trans));
2527 DBUG_RETURN(next_result(buf));
2530 static
2532 guess_scan_flags(NdbOperation::LockMode lm,
2533 const NDBTAB* tab, const MY_BITMAP* readset)
2535 int flags= 0;
2536 flags|= (lm == NdbOperation::LM_Read) ? NdbScanOperation::SF_KeyInfo : 0;
2537 if (tab->checkColumns(0, 0) & 2)
2539 int ret = tab->checkColumns(readset->bitmap, no_bytes_in_map(readset));
2541 if (ret & 2)
2542 { // If disk columns...use disk scan
2543 flags |= NdbScanOperation::SF_DiskScan;
2545 else if ((ret & 4) == 0 && (lm == NdbOperation::LM_Exclusive))
2547 // If no mem column is set and exclusive...guess disk scan
2548 flags |= NdbScanOperation::SF_DiskScan;
2551 return flags;
2556 Unique index scan in NDB (full table scan with scan filter)
2559 int ha_ndbcluster::unique_index_scan(const KEY* key_info,
2560 const uchar *key,
2561 uint key_len,
2562 uchar *buf)
2564 int res;
2565 NdbScanOperation *op;
2566 NdbTransaction *trans= m_active_trans;
2567 part_id_range part_spec;
2569 DBUG_ENTER("unique_index_scan");
2570 DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
2572 NdbOperation::LockMode lm=
2573 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
2574 int flags= guess_scan_flags(lm, m_table, table->read_set);
2575 if (!(op=trans->getNdbScanOperation((const NDBTAB *) m_table)) ||
2576 op->readTuples(lm, flags, parallelism))
2577 ERR_RETURN(trans->getNdbError());
2578 m_active_cursor= op;
2580 if (m_use_partition_function)
2582 part_spec.start_part= 0;
2583 part_spec.end_part= m_part_info->get_tot_partitions() - 1;
2584 prune_partition_set(table, &part_spec);
2585 DBUG_PRINT("info", ("part_spec.start_part = %u, part_spec.end_part = %u",
2586 part_spec.start_part, part_spec.end_part));
2588 If partition pruning has found no partition in set
2589 we can return HA_ERR_END_OF_FILE
2590 If partition pruning has found exactly one partition in set
2591 we can optimize scan to run towards that partition only.
2593 if (part_spec.start_part > part_spec.end_part)
2595 DBUG_RETURN(HA_ERR_END_OF_FILE);
2597 else if (part_spec.start_part == part_spec.end_part)
2600 Only one partition is required to scan, if sorted is required we
2601 don't need it any more since output from one ordered partitioned
2602 index is always sorted.
2604 m_active_cursor->setPartitionId(part_spec.start_part);
2606 // If table has user defined partitioning
2607 // and no primary key, we need to read the partition id
2608 // to support ORDER BY queries
2609 if ((table_share->primary_key == MAX_KEY) &&
2610 (get_ndb_partition_id(op)))
2611 ERR_RETURN(trans->getNdbError());
2613 if (!m_cond)
2614 m_cond= new ha_ndbcluster_cond;
2615 if (!m_cond)
2617 my_errno= HA_ERR_OUT_OF_MEM;
2618 DBUG_RETURN(my_errno);
2620 if (m_cond->generate_scan_filter_from_key(op, key_info, key, key_len, buf))
2621 DBUG_RETURN(ndb_err(trans));
2622 if ((res= define_read_attrs(buf, op)))
2623 DBUG_RETURN(res);
2625 if (execute_no_commit(this,trans,FALSE) != 0)
2626 DBUG_RETURN(ndb_err(trans));
2627 DBUG_PRINT("exit", ("Scan started successfully"));
2628 DBUG_RETURN(next_result(buf));
2633 Start full table scan in NDB.
2635 int ha_ndbcluster::full_table_scan(uchar *buf)
2637 int res;
2638 NdbScanOperation *op;
2639 NdbTransaction *trans= m_active_trans;
2640 part_id_range part_spec;
2642 DBUG_ENTER("full_table_scan");
2643 DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname));
2644 m_write_op= FALSE;
2646 NdbOperation::LockMode lm=
2647 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
2648 int flags= guess_scan_flags(lm, m_table, table->read_set);
2649 if (!(op=trans->getNdbScanOperation(m_table)) ||
2650 op->readTuples(lm, flags, parallelism))
2651 ERR_RETURN(trans->getNdbError());
2652 m_active_cursor= op;
2654 if (m_use_partition_function)
2656 part_spec.start_part= 0;
2657 part_spec.end_part= m_part_info->get_tot_partitions() - 1;
2658 prune_partition_set(table, &part_spec);
2659 DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
2660 part_spec.start_part, part_spec.end_part));
2662 If partition pruning has found no partition in set
2663 we can return HA_ERR_END_OF_FILE
2664 If partition pruning has found exactly one partition in set
2665 we can optimize scan to run towards that partition only.
2667 if (part_spec.start_part > part_spec.end_part)
2669 DBUG_RETURN(HA_ERR_END_OF_FILE);
2671 else if (part_spec.start_part == part_spec.end_part)
2674 Only one partition is required to scan, if sorted is required we
2675 don't need it any more since output from one ordered partitioned
2676 index is always sorted.
2678 m_active_cursor->setPartitionId(part_spec.start_part);
2680 // If table has user defined partitioning
2681 // and no primary key, we need to read the partition id
2682 // to support ORDER BY queries
2683 if ((table_share->primary_key == MAX_KEY) &&
2684 (get_ndb_partition_id(op)))
2685 ERR_RETURN(trans->getNdbError());
2688 if (m_cond && m_cond->generate_scan_filter(op))
2689 DBUG_RETURN(ndb_err(trans));
2690 if ((res= define_read_attrs(buf, op)))
2691 DBUG_RETURN(res);
2693 if (execute_no_commit(this,trans,FALSE) != 0)
2694 DBUG_RETURN(ndb_err(trans));
2695 DBUG_PRINT("exit", ("Scan started successfully"));
2696 DBUG_RETURN(next_result(buf));
2700 ha_ndbcluster::set_auto_inc(Field *field)
2702 DBUG_ENTER("ha_ndbcluster::set_auto_inc");
2703 Ndb *ndb= get_ndb();
2704 bool read_bit= bitmap_is_set(table->read_set, field->field_index);
2705 bitmap_set_bit(table->read_set, field->field_index);
2706 Uint64 next_val= (Uint64) field->val_int() + 1;
2707 if (!read_bit)
2708 bitmap_clear_bit(table->read_set, field->field_index);
2709 #ifndef DBUG_OFF
2710 char buff[22];
2711 DBUG_PRINT("info",
2712 ("Trying to set next auto increment value to %s",
2713 llstr(next_val, buff)));
2714 #endif
2715 if (ndb->checkUpdateAutoIncrementValue(m_share->tuple_id_range, next_val))
2717 Ndb_tuple_id_range_guard g(m_share);
2718 if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE)
2719 == -1)
2720 ERR_RETURN(ndb->getNdbError());
2722 DBUG_RETURN(0);
2726 Insert one record into NDB.
2728 int ha_ndbcluster::write_row(uchar *record)
2730 bool has_auto_increment;
2731 uint i;
2732 NdbTransaction *trans= m_active_trans;
2733 NdbOperation *op;
2734 int res;
2735 THD *thd= table->in_use;
2736 longlong func_value= 0;
2737 DBUG_ENTER("ha_ndbcluster::write_row");
2739 m_write_op= TRUE;
2740 has_auto_increment= (table->next_number_field && record == table->record[0]);
2741 if (table_share->primary_key != MAX_KEY)
2744 * Increase any auto_incremented primary key
2746 if (has_auto_increment)
2748 int error;
2750 m_skip_auto_increment= FALSE;
2751 if ((error= update_auto_increment()))
2752 DBUG_RETURN(error);
2753 m_skip_auto_increment= (insert_id_for_cur_row == 0);
2758 * If IGNORE the ignore constraint violations on primary and unique keys
2760 if (!m_use_write && m_ignore_dup_key)
2763 compare if expression with that in start_bulk_insert()
2764 start_bulk_insert will set parameters to ensure that each
2765 write_row is committed individually
2767 int peek_res= peek_indexed_rows(record, NDB_INSERT);
2769 if (!peek_res)
2771 DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
2773 if (peek_res != HA_ERR_KEY_NOT_FOUND)
2774 DBUG_RETURN(peek_res);
2777 ha_statistic_increment(&SSV::ha_write_count);
2778 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
2779 table->timestamp_field->set_time();
2781 if (!(op= trans->getNdbOperation(m_table)))
2782 ERR_RETURN(trans->getNdbError());
2784 res= (m_use_write) ? op->writeTuple() :op->insertTuple();
2785 if (res != 0)
2786 ERR_RETURN(trans->getNdbError());
2788 if (m_use_partition_function)
2790 uint32 part_id;
2791 int error;
2792 my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
2793 error= m_part_info->get_partition_id(m_part_info, &part_id, &func_value);
2794 dbug_tmp_restore_column_map(table->read_set, old_map);
2795 if (error)
2797 m_part_info->err_value= func_value;
2798 DBUG_RETURN(error);
2800 op->setPartitionId(part_id);
2803 if (table_share->primary_key == MAX_KEY)
2805 // Table has hidden primary key
2806 Ndb *ndb= get_ndb();
2807 Uint64 auto_value;
2808 uint retries= NDB_AUTO_INCREMENT_RETRIES;
2809 int retry_sleep= 30; /* 30 milliseconds, transaction */
2810 for (;;)
2812 Ndb_tuple_id_range_guard g(m_share);
2813 if (ndb->getAutoIncrementValue(m_table, g.range, auto_value, 1) == -1)
2815 if (--retries &&
2816 ndb->getNdbError().status == NdbError::TemporaryError)
2818 my_sleep(retry_sleep);
2819 continue;
2821 ERR_RETURN(ndb->getNdbError());
2823 break;
2825 if (set_hidden_key(op, table_share->fields, (const uchar*)&auto_value))
2826 ERR_RETURN(op->getNdbError());
2828 else
2830 int error;
2831 if ((error= set_primary_key_from_record(op, record)))
2832 DBUG_RETURN(error);
2835 // Set non-key attribute(s)
2836 bool set_blob_value= FALSE;
2837 my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
2838 for (i= 0; i < table_share->fields; i++)
2840 Field *field= table->field[i];
2841 if (!(field->flags & PRI_KEY_FLAG) &&
2842 (bitmap_is_set(table->write_set, i) || !m_use_write) &&
2843 set_ndb_value(op, field, i, record-table->record[0], &set_blob_value))
2845 m_skip_auto_increment= TRUE;
2846 dbug_tmp_restore_column_map(table->read_set, old_map);
2847 ERR_RETURN(op->getNdbError());
2850 dbug_tmp_restore_column_map(table->read_set, old_map);
2852 if (m_use_partition_function)
2855 We need to set the value of the partition function value in
2856 NDB since the NDB kernel doesn't have easy access to the function
2857 to calculate the value.
2859 if (func_value >= INT_MAX32)
2860 func_value= INT_MAX32;
2861 uint32 part_func_value= (uint32)func_value;
2862 uint no_fields= table_share->fields;
2863 if (table_share->primary_key == MAX_KEY)
2864 no_fields++;
2865 op->setValue(no_fields, part_func_value);
2868 if (unlikely(m_slow_path))
2871 ignore TNTO_NO_LOGGING for slave thd. It is used to indicate
2872 log-slave-updates option. This is instead handled in the
2873 injector thread, by looking explicitly at the
2874 opt_log_slave_updates flag.
2876 Thd_ndb *thd_ndb= get_thd_ndb(thd);
2877 if (thd->slave_thread)
2878 op->setAnyValue(thd->server_id);
2879 else if (thd_ndb->trans_options & TNTO_NO_LOGGING)
2880 op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
2882 m_rows_changed++;
2885 Execute write operation
2886 NOTE When doing inserts with many values in
2887 each INSERT statement it should not be necessary
2888 to NoCommit the transaction between each row.
2889 Find out how this is detected!
2891 m_rows_inserted++;
2892 no_uncommitted_rows_update(1);
2893 m_bulk_insert_not_flushed= TRUE;
2894 if ((m_rows_to_insert == (ha_rows) 1) ||
2895 ((m_rows_inserted % m_bulk_insert_rows) == 0) ||
2896 m_primary_key_update ||
2897 set_blob_value)
2899 // Send rows to NDB
2900 DBUG_PRINT("info", ("Sending inserts to NDB, "\
2901 "rows_inserted: %d bulk_insert_rows: %d",
2902 (int)m_rows_inserted, (int)m_bulk_insert_rows));
2904 m_bulk_insert_not_flushed= FALSE;
2905 if (m_transaction_on)
2907 if (execute_no_commit(this,trans,FALSE) != 0)
2909 m_skip_auto_increment= TRUE;
2910 no_uncommitted_rows_execute_failure();
2911 DBUG_RETURN(ndb_err(trans));
2914 else
2916 if (execute_commit(this,trans) != 0)
2918 m_skip_auto_increment= TRUE;
2919 no_uncommitted_rows_execute_failure();
2920 DBUG_RETURN(ndb_err(trans));
2922 if (trans->restart() != 0)
2924 DBUG_ASSERT(0);
2925 DBUG_RETURN(-1);
2929 if ((has_auto_increment) && (m_skip_auto_increment))
2931 int ret_val;
2932 if ((ret_val= set_auto_inc(table->next_number_field)))
2934 DBUG_RETURN(ret_val);
2937 m_skip_auto_increment= TRUE;
2939 DBUG_PRINT("exit",("ok"));
2940 DBUG_RETURN(0);
2945 Compare if a key in a row has changed.
2948 int ha_ndbcluster::key_cmp(uint keynr, const uchar * old_row,
2949 const uchar * new_row)
2951 KEY_PART_INFO *key_part=table->key_info[keynr].key_part;
2952 KEY_PART_INFO *end=key_part+table->key_info[keynr].key_parts;
2954 for (; key_part != end ; key_part++)
2956 if (key_part->null_bit)
2958 if ((old_row[key_part->null_offset] & key_part->null_bit) !=
2959 (new_row[key_part->null_offset] & key_part->null_bit))
2960 return 1;
2962 if (key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART))
2965 if (key_part->field->cmp_binary((old_row + key_part->offset),
2966 (new_row + key_part->offset),
2967 (ulong) key_part->length))
2968 return 1;
2970 else
2972 if (memcmp(old_row+key_part->offset, new_row+key_part->offset,
2973 key_part->length))
2974 return 1;
2977 return 0;
2981 Update one record in NDB using primary key.
2984 int ha_ndbcluster::update_row(const uchar *old_data, uchar *new_data)
2986 THD *thd= table->in_use;
2987 NdbTransaction *trans= m_active_trans;
2988 NdbScanOperation* cursor= m_active_cursor;
2989 NdbOperation *op;
2990 uint i;
2991 uint32 old_part_id= 0, new_part_id= 0;
2992 int error;
2993 longlong func_value;
2994 bool pk_update= (table_share->primary_key != MAX_KEY &&
2995 key_cmp(table_share->primary_key, old_data, new_data));
2996 DBUG_ENTER("update_row");
2997 m_write_op= TRUE;
3000 * If IGNORE the ignore constraint violations on primary and unique keys,
3001 * but check that it is not part of INSERT ... ON DUPLICATE KEY UPDATE
3003 if (m_ignore_dup_key && (thd->lex->sql_command == SQLCOM_UPDATE ||
3004 thd->lex->sql_command == SQLCOM_UPDATE_MULTI))
3006 NDB_WRITE_OP write_op= (pk_update) ? NDB_PK_UPDATE : NDB_UPDATE;
3007 int peek_res= peek_indexed_rows(new_data, write_op);
3009 if (!peek_res)
3011 DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY);
3013 if (peek_res != HA_ERR_KEY_NOT_FOUND)
3014 DBUG_RETURN(peek_res);
3017 ha_statistic_increment(&SSV::ha_update_count);
3018 if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
3020 table->timestamp_field->set_time();
3021 bitmap_set_bit(table->write_set, table->timestamp_field->field_index);
3024 if (m_use_partition_function &&
3025 (error= get_parts_for_update(old_data, new_data, table->record[0],
3026 m_part_info, &old_part_id, &new_part_id,
3027 &func_value)))
3029 m_part_info->err_value= func_value;
3030 DBUG_RETURN(error);
3034 * Check for update of primary key or partition change
3035 * for special handling
3037 if (pk_update || old_part_id != new_part_id)
3039 int read_res, insert_res, delete_res, undo_res;
3041 DBUG_PRINT("info", ("primary key update or partition change, "
3042 "doing read+delete+insert"));
3043 // Get all old fields, since we optimize away fields not in query
3044 read_res= complemented_read(old_data, new_data, old_part_id);
3045 if (read_res)
3047 DBUG_PRINT("info", ("read failed"));
3048 DBUG_RETURN(read_res);
3050 // Delete old row
3051 m_primary_key_update= TRUE;
3052 delete_res= delete_row(old_data);
3053 m_primary_key_update= FALSE;
3054 if (delete_res)
3056 DBUG_PRINT("info", ("delete failed"));
3057 DBUG_RETURN(delete_res);
3059 // Insert new row
3060 DBUG_PRINT("info", ("delete succeded"));
3061 m_primary_key_update= TRUE;
3063 If we are updating a primary key with auto_increment
3064 then we need to update the auto_increment counter
3066 if (table->found_next_number_field &&
3067 bitmap_is_set(table->write_set,
3068 table->found_next_number_field->field_index) &&
3069 (error= set_auto_inc(table->found_next_number_field)))
3071 DBUG_RETURN(error);
3073 insert_res= write_row(new_data);
3074 m_primary_key_update= FALSE;
3075 if (insert_res)
3077 DBUG_PRINT("info", ("insert failed"));
3078 if (trans->commitStatus() == NdbConnection::Started)
3080 // Undo delete_row(old_data)
3081 m_primary_key_update= TRUE;
3082 undo_res= write_row((uchar *)old_data);
3083 if (undo_res)
3084 push_warning(current_thd,
3085 MYSQL_ERROR::WARN_LEVEL_WARN,
3086 undo_res,
3087 "NDB failed undoing delete at primary key update");
3088 m_primary_key_update= FALSE;
3090 DBUG_RETURN(insert_res);
3092 DBUG_PRINT("info", ("delete+insert succeeded"));
3093 DBUG_RETURN(0);
3096 If we are updating a unique key with auto_increment
3097 then we need to update the auto_increment counter
3099 if (table->found_next_number_field &&
3100 bitmap_is_set(table->write_set,
3101 table->found_next_number_field->field_index) &&
3102 (error= set_auto_inc(table->found_next_number_field)))
3104 DBUG_RETURN(error);
3106 if (cursor)
3109 We are scanning records and want to update the record
3110 that was just found, call updateTuple on the cursor
3111 to take over the lock to a new update operation
3112 And thus setting the primary key of the record from
3113 the active record in cursor
3115 DBUG_PRINT("info", ("Calling updateTuple on cursor"));
3116 if (!(op= cursor->updateCurrentTuple()))
3117 ERR_RETURN(trans->getNdbError());
3118 m_lock_tuple= FALSE;
3119 m_ops_pending++;
3120 if (uses_blob_value())
3121 m_blobs_pending= TRUE;
3122 if (m_use_partition_function)
3123 cursor->setPartitionId(new_part_id);
3125 else
3127 if (!(op= trans->getNdbOperation(m_table)) ||
3128 op->updateTuple() != 0)
3129 ERR_RETURN(trans->getNdbError());
3131 if (m_use_partition_function)
3132 op->setPartitionId(new_part_id);
3133 if (table_share->primary_key == MAX_KEY)
3135 // This table has no primary key, use "hidden" primary key
3136 DBUG_PRINT("info", ("Using hidden key"));
3138 // Require that the PK for this record has previously been
3139 // read into m_ref
3140 DBUG_DUMP("key", m_ref, NDB_HIDDEN_PRIMARY_KEY_LENGTH);
3142 if (set_hidden_key(op, table->s->fields, m_ref))
3143 ERR_RETURN(op->getNdbError());
3145 else
3147 int res;
3148 if ((res= set_primary_key_from_record(op, old_data)))
3149 DBUG_RETURN(res);
3153 m_rows_changed++;
3155 // Set non-key attribute(s)
3156 my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
3157 for (i= 0; i < table_share->fields; i++)
3159 Field *field= table->field[i];
3160 if (bitmap_is_set(table->write_set, i) &&
3161 (!(field->flags & PRI_KEY_FLAG)) &&
3162 set_ndb_value(op, field, i, new_data - table->record[0]))
3164 dbug_tmp_restore_column_map(table->read_set, old_map);
3165 ERR_RETURN(op->getNdbError());
3168 dbug_tmp_restore_column_map(table->read_set, old_map);
3170 if (m_use_partition_function)
3172 if (func_value >= INT_MAX32)
3173 func_value= INT_MAX32;
3174 uint32 part_func_value= (uint32)func_value;
3175 uint no_fields= table_share->fields;
3176 if (table_share->primary_key == MAX_KEY)
3177 no_fields++;
3178 op->setValue(no_fields, part_func_value);
3181 if (unlikely(m_slow_path))
3184 ignore TNTO_NO_LOGGING for slave thd. It is used to indicate
3185 log-slave-updates option. This is instead handled in the
3186 injector thread, by looking explicitly at the
3187 opt_log_slave_updates flag.
3189 Thd_ndb *thd_ndb= get_thd_ndb(thd);
3190 if (thd->slave_thread)
3191 op->setAnyValue(thd->server_id);
3192 else if (thd_ndb->trans_options & TNTO_NO_LOGGING)
3193 op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
3196 Execute update operation if we are not doing a scan for update
3197 and there exist UPDATE AFTER triggers
3200 if ((!cursor || m_update_cannot_batch) &&
3201 execute_no_commit(this,trans,false) != 0) {
3202 no_uncommitted_rows_execute_failure();
3203 DBUG_RETURN(ndb_err(trans));
3206 DBUG_RETURN(0);
3211 Delete one record from NDB, using primary key .
3214 int ha_ndbcluster::delete_row(const uchar *record)
3216 THD *thd= table->in_use;
3217 NdbTransaction *trans= m_active_trans;
3218 NdbScanOperation* cursor= m_active_cursor;
3219 NdbOperation *op;
3220 uint32 part_id;
3221 int error;
3222 DBUG_ENTER("delete_row");
3223 m_write_op= TRUE;
3225 ha_statistic_increment(&SSV::ha_delete_count);
3226 m_rows_changed++;
3228 if (m_use_partition_function &&
3229 (error= get_part_for_delete(record, table->record[0], m_part_info,
3230 &part_id)))
3232 DBUG_RETURN(error);
3235 if (cursor)
3238 We are scanning records and want to delete the record
3239 that was just found, call deleteTuple on the cursor
3240 to take over the lock to a new delete operation
3241 And thus setting the primary key of the record from
3242 the active record in cursor
3244 DBUG_PRINT("info", ("Calling deleteTuple on cursor"));
3245 if (cursor->deleteCurrentTuple() != 0)
3246 ERR_RETURN(trans->getNdbError());
3247 m_lock_tuple= FALSE;
3248 m_ops_pending++;
3250 if (m_use_partition_function)
3251 cursor->setPartitionId(part_id);
3253 no_uncommitted_rows_update(-1);
3255 if (unlikely(m_slow_path))
3258 ignore TNTO_NO_LOGGING for slave thd. It is used to indicate
3259 log-slave-updates option. This is instead handled in the
3260 injector thread, by looking explicitly at the
3261 opt_log_slave_updates flag.
3263 Thd_ndb *thd_ndb= get_thd_ndb(thd);
3264 if (thd->slave_thread)
3265 ((NdbOperation *)trans->getLastDefinedOperation())->
3266 setAnyValue(thd->server_id);
3267 else if (thd_ndb->trans_options & TNTO_NO_LOGGING)
3268 ((NdbOperation *)trans->getLastDefinedOperation())->
3269 setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
3271 if (!(m_primary_key_update || m_delete_cannot_batch))
3272 // If deleting from cursor, NoCommit will be handled in next_result
3273 DBUG_RETURN(0);
3275 else
3278 if (!(op=trans->getNdbOperation(m_table)) ||
3279 op->deleteTuple() != 0)
3280 ERR_RETURN(trans->getNdbError());
3282 if (m_use_partition_function)
3283 op->setPartitionId(part_id);
3285 no_uncommitted_rows_update(-1);
3287 if (table_share->primary_key == MAX_KEY)
3289 // This table has no primary key, use "hidden" primary key
3290 DBUG_PRINT("info", ("Using hidden key"));
3292 if (set_hidden_key(op, table->s->fields, m_ref))
3293 ERR_RETURN(op->getNdbError());
3295 else
3297 if ((error= set_primary_key_from_record(op, record)))
3298 DBUG_RETURN(error);
3301 if (unlikely(m_slow_path))
3304 ignore TNTO_NO_LOGGING for slave thd. It is used to indicate
3305 log-slave-updates option. This is instead handled in the
3306 injector thread, by looking explicitly at the
3307 opt_log_slave_updates flag.
3309 Thd_ndb *thd_ndb= get_thd_ndb(thd);
3310 if (thd->slave_thread)
3311 op->setAnyValue(thd->server_id);
3312 else if (thd_ndb->trans_options & TNTO_NO_LOGGING)
3313 op->setAnyValue(NDB_ANYVALUE_FOR_NOLOGGING);
3317 // Execute delete operation
3318 if (execute_no_commit(this,trans,FALSE) != 0) {
3319 no_uncommitted_rows_execute_failure();
3320 DBUG_RETURN(ndb_err(trans));
3322 DBUG_RETURN(0);
3326 Unpack a record read from NDB.
3328 @param buf Buffer to store read row
3330 @note
3331 The data for each row is read directly into the
3332 destination buffer. This function is primarily
3333 called in order to check if any fields should be
3334 set to null.
3337 void ndb_unpack_record(TABLE *table, NdbValue *value,
3338 MY_BITMAP *defined, uchar *buf)
3340 Field **p_field= table->field, *field= *p_field;
3341 my_ptrdiff_t row_offset= (my_ptrdiff_t) (buf - table->record[0]);
3342 my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
3343 DBUG_ENTER("ndb_unpack_record");
3346 Set the filler bits of the null byte, since they are
3347 not touched in the code below.
3349 The filler bits are the MSBs in the last null byte
3351 if (table->s->null_bytes > 0)
3352 buf[table->s->null_bytes - 1]|= 256U - (1U <<
3353 table->s->last_null_bit_pos);
3355 Set null flag(s)
3357 for ( ; field;
3358 p_field++, value++, field= *p_field)
3360 field->set_notnull(row_offset);
3361 if ((*value).ptr)
3363 if (!(field->flags & BLOB_FLAG))
3365 int is_null= (*value).rec->isNULL();
3366 if (is_null)
3368 if (is_null > 0)
3370 DBUG_PRINT("info",("[%u] NULL",
3371 (*value).rec->getColumn()->getColumnNo()));
3372 field->set_null(row_offset);
3374 else
3376 DBUG_PRINT("info",("[%u] UNDEFINED",
3377 (*value).rec->getColumn()->getColumnNo()));
3378 bitmap_clear_bit(defined,
3379 (*value).rec->getColumn()->getColumnNo());
3382 else if (field->type() == MYSQL_TYPE_BIT)
3384 Field_bit *field_bit= static_cast<Field_bit*>(field);
3387 Move internal field pointer to point to 'buf'. Calling
3388 the correct member function directly since we know the
3389 type of the object.
3391 field_bit->Field_bit::move_field_offset(row_offset);
3392 if (field->pack_length() < 5)
3394 DBUG_PRINT("info", ("bit field H'%.8X",
3395 (*value).rec->u_32_value()));
3396 field_bit->Field_bit::store((longlong) (*value).rec->u_32_value(),
3397 FALSE);
3399 else
3401 DBUG_PRINT("info", ("bit field H'%.8X%.8X",
3402 *(Uint32 *)(*value).rec->aRef(),
3403 *((Uint32 *)(*value).rec->aRef()+1)));
3404 #ifdef WORDS_BIGENDIAN
3405 /* lsw is stored first */
3406 Uint32 *buf= (Uint32 *)(*value).rec->aRef();
3407 field_bit->Field_bit::store((((longlong)*buf)
3408 & 0x000000000FFFFFFFFLL)
3410 ((((longlong)*(buf+1)) << 32)
3411 & 0xFFFFFFFF00000000LL),
3412 TRUE);
3413 #else
3414 field_bit->Field_bit::store((longlong)
3415 (*value).rec->u_64_value(), TRUE);
3416 #endif
3419 Move back internal field pointer to point to original
3420 value (usually record[0]).
3422 field_bit->Field_bit::move_field_offset(-row_offset);
3423 DBUG_PRINT("info",("[%u] SET",
3424 (*value).rec->getColumn()->getColumnNo()));
3425 DBUG_DUMP("info", field->ptr, field->pack_length());
3427 else
3429 DBUG_PRINT("info",("[%u] SET",
3430 (*value).rec->getColumn()->getColumnNo()));
3431 DBUG_DUMP("info", field->ptr, field->pack_length());
3434 else
3436 NdbBlob *ndb_blob= (*value).blob;
3437 uint col_no = ndb_blob->getColumn()->getColumnNo();
3438 int isNull;
3439 ndb_blob->getDefined(isNull);
3440 if (isNull == 1)
3442 DBUG_PRINT("info",("[%u] NULL", col_no));
3443 field->set_null(row_offset);
3445 else if (isNull == -1)
3447 DBUG_PRINT("info",("[%u] UNDEFINED", col_no));
3448 bitmap_clear_bit(defined, col_no);
3450 else
3452 #ifndef DBUG_OFF
3453 // pointer vas set in get_ndb_blobs_value
3454 Field_blob *field_blob= (Field_blob*)field;
3455 uchar *ptr;
3456 field_blob->get_ptr(&ptr, row_offset);
3457 uint32 len= field_blob->get_length(row_offset);
3458 DBUG_PRINT("info",("[%u] SET ptr: 0x%lx len: %u",
3459 col_no, (long) ptr, len));
3460 #endif
3465 dbug_tmp_restore_column_map(table->write_set, old_map);
3466 DBUG_VOID_RETURN;
3469 void ha_ndbcluster::unpack_record(uchar *buf)
3471 ndb_unpack_record(table, m_value, 0, buf);
3472 #ifndef DBUG_OFF
3473 // Read and print all values that was fetched
3474 if (table_share->primary_key == MAX_KEY)
3476 // Table with hidden primary key
3477 int hidden_no= table_share->fields;
3478 const NDBTAB *tab= m_table;
3479 char buff[22];
3480 const NDBCOL *hidden_col= tab->getColumn(hidden_no);
3481 const NdbRecAttr* rec= m_value[hidden_no].rec;
3482 DBUG_ASSERT(rec);
3483 DBUG_PRINT("hidden", ("%d: %s \"%s\"", hidden_no,
3484 hidden_col->getName(),
3485 llstr(rec->u_64_value(), buff)));
3487 //DBUG_EXECUTE("value", print_results(););
3488 #endif
3492 Utility function to print/dump the fetched field.
3494 To avoid unnecessary work, wrap in DBUG_EXECUTE as in:
3495 DBUG_EXECUTE("value", print_results(););
3498 void ha_ndbcluster::print_results()
3500 DBUG_ENTER("print_results");
3502 #ifndef DBUG_OFF
3504 char buf_type[MAX_FIELD_WIDTH], buf_val[MAX_FIELD_WIDTH];
3505 String type(buf_type, sizeof(buf_type), &my_charset_bin);
3506 String val(buf_val, sizeof(buf_val), &my_charset_bin);
3507 for (uint f= 0; f < table_share->fields; f++)
3509 /* Use DBUG_PRINT since DBUG_FILE cannot be filtered out */
3510 char buf[2000];
3511 Field *field;
3512 void* ptr;
3513 NdbValue value;
3515 buf[0]= 0;
3516 field= table->field[f];
3517 if (!(value= m_value[f]).ptr)
3519 strmov(buf, "not read");
3520 goto print_value;
3523 ptr= field->ptr;
3525 if (! (field->flags & BLOB_FLAG))
3527 if (value.rec->isNULL())
3529 strmov(buf, "NULL");
3530 goto print_value;
3532 type.length(0);
3533 val.length(0);
3534 field->sql_type(type);
3535 field->val_str(&val);
3536 my_snprintf(buf, sizeof(buf), "%s %s", type.c_ptr(), val.c_ptr());
3538 else
3540 NdbBlob *ndb_blob= value.blob;
3541 bool isNull= TRUE;
3542 ndb_blob->getNull(isNull);
3543 if (isNull)
3544 strmov(buf, "NULL");
3547 print_value:
3548 DBUG_PRINT("value", ("%u,%s: %s", f, field->field_name, buf));
3550 #endif
3551 DBUG_VOID_RETURN;
3555 int ha_ndbcluster::index_init(uint index, bool sorted)
3557 DBUG_ENTER("ha_ndbcluster::index_init");
3558 DBUG_PRINT("enter", ("index: %u sorted: %d", index, sorted));
3559 active_index= index;
3560 m_sorted= sorted;
3562 Locks are are explicitly released in scan
3563 unless m_lock.type == TL_READ_HIGH_PRIORITY
3564 and no sub-sequent call to unlock_row()
3566 m_lock_tuple= FALSE;
3567 DBUG_RETURN(0);
3571 int ha_ndbcluster::index_end()
3573 DBUG_ENTER("ha_ndbcluster::index_end");
3574 DBUG_RETURN(close_scan());
3578 Check if key contains null.
3580 static
3582 check_null_in_key(const KEY* key_info, const uchar *key, uint key_len)
3584 KEY_PART_INFO *curr_part, *end_part;
3585 const uchar* end_ptr= key + key_len;
3586 curr_part= key_info->key_part;
3587 end_part= curr_part + key_info->key_parts;
3589 for (; curr_part != end_part && key < end_ptr; curr_part++)
3591 if (curr_part->null_bit && *key)
3592 return 1;
3594 key += curr_part->store_length;
3596 return 0;
3599 int ha_ndbcluster::index_read(uchar *buf,
3600 const uchar *key, uint key_len,
3601 enum ha_rkey_function find_flag)
3603 key_range start_key;
3604 bool descending= FALSE;
3605 DBUG_ENTER("ha_ndbcluster::index_read");
3606 DBUG_PRINT("enter", ("active_index: %u, key_len: %u, find_flag: %d",
3607 active_index, key_len, find_flag));
3609 start_key.key= key;
3610 start_key.length= key_len;
3611 start_key.flag= find_flag;
3612 descending= FALSE;
3613 switch (find_flag) {
3614 case HA_READ_KEY_OR_PREV:
3615 case HA_READ_BEFORE_KEY:
3616 case HA_READ_PREFIX_LAST:
3617 case HA_READ_PREFIX_LAST_OR_PREV:
3618 descending= TRUE;
3619 break;
3620 default:
3621 break;
3623 DBUG_RETURN(read_range_first_to_buf(&start_key, 0, descending,
3624 m_sorted, buf));
3628 int ha_ndbcluster::index_next(uchar *buf)
3630 DBUG_ENTER("ha_ndbcluster::index_next");
3631 ha_statistic_increment(&SSV::ha_read_next_count);
3632 DBUG_RETURN(next_result(buf));
3636 int ha_ndbcluster::index_prev(uchar *buf)
3638 DBUG_ENTER("ha_ndbcluster::index_prev");
3639 ha_statistic_increment(&SSV::ha_read_prev_count);
3640 DBUG_RETURN(next_result(buf));
3644 int ha_ndbcluster::index_first(uchar *buf)
3646 DBUG_ENTER("ha_ndbcluster::index_first");
3647 ha_statistic_increment(&SSV::ha_read_first_count);
3648 // Start the ordered index scan and fetch the first row
3650 // Only HA_READ_ORDER indexes get called by index_first
3651 DBUG_RETURN(ordered_index_scan(0, 0, TRUE, FALSE, buf, NULL));
3655 int ha_ndbcluster::index_last(uchar *buf)
3657 DBUG_ENTER("ha_ndbcluster::index_last");
3658 ha_statistic_increment(&SSV::ha_read_last_count);
3659 DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL));
3662 int ha_ndbcluster::index_read_last(uchar * buf, const uchar * key, uint key_len)
3664 DBUG_ENTER("ha_ndbcluster::index_read_last");
3665 DBUG_RETURN(index_read(buf, key, key_len, HA_READ_PREFIX_LAST));
3668 int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key,
3669 const key_range *end_key,
3670 bool desc, bool sorted,
3671 uchar* buf)
3673 part_id_range part_spec;
3674 ndb_index_type type= get_index_type(active_index);
3675 const KEY* key_info= table->key_info+active_index;
3676 int error;
3677 DBUG_ENTER("ha_ndbcluster::read_range_first_to_buf");
3678 DBUG_PRINT("info", ("desc: %d, sorted: %d", desc, sorted));
3680 if (m_use_partition_function)
3682 get_partition_set(table, buf, active_index, start_key, &part_spec);
3683 DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
3684 part_spec.start_part, part_spec.end_part));
3686 If partition pruning has found no partition in set
3687 we can return HA_ERR_END_OF_FILE
3688 If partition pruning has found exactly one partition in set
3689 we can optimize scan to run towards that partition only.
3691 if (part_spec.start_part > part_spec.end_part)
3693 DBUG_RETURN(HA_ERR_END_OF_FILE);
3695 else if (part_spec.start_part == part_spec.end_part)
3698 Only one partition is required to scan, if sorted is required we
3699 don't need it any more since output from one ordered partitioned
3700 index is always sorted.
3702 sorted= FALSE;
3706 m_write_op= FALSE;
3707 switch (type){
3708 case PRIMARY_KEY_ORDERED_INDEX:
3709 case PRIMARY_KEY_INDEX:
3710 if (start_key &&
3711 start_key->length == key_info->key_length &&
3712 start_key->flag == HA_READ_KEY_EXACT)
3714 if (m_active_cursor && (error= close_scan()))
3715 DBUG_RETURN(error);
3716 error= pk_read(start_key->key, start_key->length, buf,
3717 part_spec.start_part);
3718 DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
3720 break;
3721 case UNIQUE_ORDERED_INDEX:
3722 case UNIQUE_INDEX:
3723 if (start_key && start_key->length == key_info->key_length &&
3724 start_key->flag == HA_READ_KEY_EXACT &&
3725 !check_null_in_key(key_info, start_key->key, start_key->length))
3727 if (m_active_cursor && (error= close_scan()))
3728 DBUG_RETURN(error);
3730 error= unique_index_read(start_key->key, start_key->length, buf);
3731 DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error);
3733 else if (type == UNIQUE_INDEX)
3734 DBUG_RETURN(unique_index_scan(key_info,
3735 start_key->key,
3736 start_key->length,
3737 buf));
3738 break;
3739 default:
3740 break;
3742 // Start the ordered index scan and fetch the first row
3743 DBUG_RETURN(ordered_index_scan(start_key, end_key, sorted, desc, buf,
3744 &part_spec));
3747 int ha_ndbcluster::read_range_first(const key_range *start_key,
3748 const key_range *end_key,
3749 bool eq_r, bool sorted)
3751 uchar* buf= table->record[0];
3752 DBUG_ENTER("ha_ndbcluster::read_range_first");
3753 DBUG_RETURN(read_range_first_to_buf(start_key, end_key, FALSE,
3754 sorted, buf));
3757 int ha_ndbcluster::read_range_next()
3759 DBUG_ENTER("ha_ndbcluster::read_range_next");
3760 DBUG_RETURN(next_result(table->record[0]));
3764 int ha_ndbcluster::rnd_init(bool scan)
3766 NdbScanOperation *cursor= m_active_cursor;
3767 DBUG_ENTER("rnd_init");
3768 DBUG_PRINT("enter", ("scan: %d", scan));
3769 // Check if scan is to be restarted
3770 if (cursor)
3772 if (!scan)
3773 DBUG_RETURN(1);
3774 if (cursor->restart(m_force_send) != 0)
3776 DBUG_ASSERT(0);
3777 DBUG_RETURN(-1);
3780 index_init(table_share->primary_key, 0);
3781 DBUG_RETURN(0);
3784 int ha_ndbcluster::close_scan()
3786 NdbTransaction *trans= m_active_trans;
3787 DBUG_ENTER("close_scan");
3789 m_multi_cursor= 0;
3790 if (!m_active_cursor && !m_multi_cursor)
3791 DBUG_RETURN(0);
3793 NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor;
3795 if (m_lock_tuple)
3798 Lock level m_lock.type either TL_WRITE_ALLOW_WRITE
3799 (SELECT FOR UPDATE) or TL_READ_WITH_SHARED_LOCKS (SELECT
3800 LOCK WITH SHARE MODE) and row was not explictly unlocked
3801 with unlock_row() call
3803 NdbOperation *op;
3804 // Lock row
3805 DBUG_PRINT("info", ("Keeping lock on scanned row"));
3807 if (!(op= cursor->lockCurrentTuple()))
3809 m_lock_tuple= FALSE;
3810 ERR_RETURN(trans->getNdbError());
3812 m_ops_pending++;
3814 m_lock_tuple= FALSE;
3815 if (m_ops_pending)
3818 Take over any pending transactions to the
3819 deleteing/updating transaction before closing the scan
3821 DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending));
3822 if (execute_no_commit(this,trans,FALSE) != 0) {
3823 no_uncommitted_rows_execute_failure();
3824 DBUG_RETURN(ndb_err(trans));
3826 m_ops_pending= 0;
3829 cursor->close(m_force_send, TRUE);
3830 m_active_cursor= m_multi_cursor= NULL;
3831 DBUG_RETURN(0);
3834 int ha_ndbcluster::rnd_end()
3836 DBUG_ENTER("rnd_end");
3837 DBUG_RETURN(close_scan());
3841 int ha_ndbcluster::rnd_next(uchar *buf)
3843 DBUG_ENTER("rnd_next");
3844 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
3846 if (!m_active_cursor)
3847 DBUG_RETURN(full_table_scan(buf));
3848 DBUG_RETURN(next_result(buf));
3853 An "interesting" record has been found and it's pk
3854 retrieved by calling position. Now it's time to read
3855 the record from db once again.
3858 int ha_ndbcluster::rnd_pos(uchar *buf, uchar *pos)
3860 DBUG_ENTER("rnd_pos");
3861 ha_statistic_increment(&SSV::ha_read_rnd_count);
3862 // The primary key for the record is stored in pos
3863 // Perform a pk_read using primary key "index"
3865 part_id_range part_spec;
3866 uint key_length= ref_length;
3867 if (m_use_partition_function)
3869 if (table_share->primary_key == MAX_KEY)
3872 The partition id has been fetched from ndb
3873 and has been stored directly after the hidden key
3875 DBUG_DUMP("key+part", pos, key_length);
3876 key_length= ref_length - sizeof(m_part_id);
3877 part_spec.start_part= part_spec.end_part= *(uint32 *)(pos + key_length);
3879 else
3881 key_range key_spec;
3882 KEY *key_info= table->key_info + table_share->primary_key;
3883 key_spec.key= pos;
3884 key_spec.length= key_length;
3885 key_spec.flag= HA_READ_KEY_EXACT;
3886 get_full_part_id_from_key(table, buf, key_info,
3887 &key_spec, &part_spec);
3888 DBUG_ASSERT(part_spec.start_part == part_spec.end_part);
3890 DBUG_PRINT("info", ("partition id %u", part_spec.start_part));
3892 DBUG_DUMP("key", pos, key_length);
3893 DBUG_RETURN(pk_read(pos, key_length, buf, part_spec.start_part));
3899 Store the primary key of this record in ref
3900 variable, so that the row can be retrieved again later
3901 using "reference" in rnd_pos.
3904 void ha_ndbcluster::position(const uchar *record)
3906 KEY *key_info;
3907 KEY_PART_INFO *key_part;
3908 KEY_PART_INFO *end;
3909 uchar *buff;
3910 uint key_length;
3912 DBUG_ENTER("position");
3914 if (table_share->primary_key != MAX_KEY)
3916 key_length= ref_length;
3917 key_info= table->key_info + table_share->primary_key;
3918 key_part= key_info->key_part;
3919 end= key_part + key_info->key_parts;
3920 buff= ref;
3922 for (; key_part != end; key_part++)
3924 if (key_part->null_bit) {
3925 /* Store 0 if the key part is a NULL part */
3926 if (record[key_part->null_offset]
3927 & key_part->null_bit) {
3928 *buff++= 1;
3929 continue;
3931 *buff++= 0;
3934 size_t len = key_part->length;
3935 const uchar * ptr = record + key_part->offset;
3936 Field *field = key_part->field;
3937 if (field->type() == MYSQL_TYPE_VARCHAR)
3939 if (((Field_varstring*)field)->length_bytes == 1)
3942 * Keys always use 2 bytes length
3944 buff[0] = ptr[0];
3945 buff[1] = 0;
3946 memcpy(buff+2, ptr + 1, len);
3948 else
3950 memcpy(buff, ptr, len + 2);
3952 len += 2;
3954 else
3956 memcpy(buff, ptr, len);
3958 buff += len;
3961 else
3963 // No primary key, get hidden key
3964 DBUG_PRINT("info", ("Getting hidden key"));
3965 // If table has user defined partition save the partition id as well
3966 if(m_use_partition_function)
3968 DBUG_PRINT("info", ("Saving partition id %u", m_part_id));
3969 key_length= ref_length - sizeof(m_part_id);
3970 memcpy(ref+key_length, (void *)&m_part_id, sizeof(m_part_id));
3972 else
3973 key_length= ref_length;
3974 #ifndef DBUG_OFF
3975 int hidden_no= table->s->fields;
3976 const NDBTAB *tab= m_table;
3977 const NDBCOL *hidden_col= tab->getColumn(hidden_no);
3978 DBUG_ASSERT(hidden_col->getPrimaryKey() &&
3979 hidden_col->getAutoIncrement() &&
3980 key_length == NDB_HIDDEN_PRIMARY_KEY_LENGTH);
3981 #endif
3982 memcpy(ref, m_ref, key_length);
3984 #ifndef DBUG_OFF
3985 if (table_share->primary_key == MAX_KEY && m_use_partition_function)
3986 DBUG_DUMP("key+part", ref, key_length+sizeof(m_part_id));
3987 #endif
3988 DBUG_DUMP("ref", ref, key_length);
3989 DBUG_VOID_RETURN;
3993 int ha_ndbcluster::info(uint flag)
3995 int result= 0;
3996 DBUG_ENTER("info");
3997 DBUG_PRINT("enter", ("flag: %d", flag));
3999 if (flag & HA_STATUS_POS)
4000 DBUG_PRINT("info", ("HA_STATUS_POS"));
4001 if (flag & HA_STATUS_NO_LOCK)
4002 DBUG_PRINT("info", ("HA_STATUS_NO_LOCK"));
4003 if (flag & HA_STATUS_TIME)
4004 DBUG_PRINT("info", ("HA_STATUS_TIME"));
4005 if (flag & HA_STATUS_VARIABLE)
4007 DBUG_PRINT("info", ("HA_STATUS_VARIABLE"));
4008 if (m_table_info)
4010 if (m_ha_not_exact_count)
4011 stats.records= 100;
4012 else
4013 result= records_update();
4015 else
4017 if ((my_errno= check_ndb_connection()))
4018 DBUG_RETURN(my_errno);
4019 Ndb *ndb= get_ndb();
4020 ndb->setDatabaseName(m_dbname);
4021 struct Ndb_statistics stat;
4022 if (ndb->setDatabaseName(m_dbname))
4024 DBUG_RETURN(my_errno= HA_ERR_OUT_OF_MEM);
4026 if (current_thd->variables.ndb_use_exact_count &&
4027 (result= ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat))
4028 == 0)
4030 stats.mean_rec_length= stat.row_size;
4031 stats.data_file_length= stat.fragment_memory;
4032 stats.records= stat.row_count;
4034 else
4036 stats.mean_rec_length= 0;
4037 stats.records= 100;
4041 if (flag & HA_STATUS_CONST)
4043 DBUG_PRINT("info", ("HA_STATUS_CONST"));
4044 set_rec_per_key();
4046 if (flag & HA_STATUS_ERRKEY)
4048 DBUG_PRINT("info", ("HA_STATUS_ERRKEY"));
4049 errkey= m_dupkey;
4051 if (flag & HA_STATUS_AUTO)
4053 DBUG_PRINT("info", ("HA_STATUS_AUTO"));
4054 if (m_table && table->found_next_number_field)
4056 if ((my_errno= check_ndb_connection()))
4057 DBUG_RETURN(my_errno);
4058 Ndb *ndb= get_ndb();
4059 Ndb_tuple_id_range_guard g(m_share);
4061 Uint64 auto_increment_value64;
4062 if (ndb->readAutoIncrementValue(m_table, g.range,
4063 auto_increment_value64) == -1)
4065 const NdbError err= ndb->getNdbError();
4066 sql_print_error("Error %lu in readAutoIncrementValue(): %s",
4067 (ulong) err.code, err.message);
4068 stats.auto_increment_value= ~(ulonglong)0;
4070 else
4071 stats.auto_increment_value= (ulonglong)auto_increment_value64;
4075 if(result == -1)
4076 result= HA_ERR_NO_CONNECTION;
4078 DBUG_RETURN(result);
4082 void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info,
4083 uint part_id)
4086 This functions should be fixed. Suggested fix: to
4087 implement ndb function which retrives the statistics
4088 about ndb partitions.
4090 bzero((char*) stat_info, sizeof(PARTITION_INFO));
4091 return;
4095 int ha_ndbcluster::extra(enum ha_extra_function operation)
4097 DBUG_ENTER("extra");
4098 switch (operation) {
4099 case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/
4100 DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY"));
4101 DBUG_PRINT("info", ("Ignoring duplicate key"));
4102 m_ignore_dup_key= TRUE;
4103 break;
4104 case HA_EXTRA_NO_IGNORE_DUP_KEY:
4105 DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY"));
4106 m_ignore_dup_key= FALSE;
4107 break;
4108 case HA_EXTRA_IGNORE_NO_KEY:
4109 DBUG_PRINT("info", ("HA_EXTRA_IGNORE_NO_KEY"));
4110 DBUG_PRINT("info", ("Turning on AO_IgnoreError at Commit/NoCommit"));
4111 m_ignore_no_key= TRUE;
4112 break;
4113 case HA_EXTRA_NO_IGNORE_NO_KEY:
4114 DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_NO_KEY"));
4115 DBUG_PRINT("info", ("Turning on AO_IgnoreError at Commit/NoCommit"));
4116 m_ignore_no_key= FALSE;
4117 break;
4118 case HA_EXTRA_WRITE_CAN_REPLACE:
4119 DBUG_PRINT("info", ("HA_EXTRA_WRITE_CAN_REPLACE"));
4120 if (!m_has_unique_index ||
4121 current_thd->slave_thread) /* always set if slave, quick fix for bug 27378 */
4123 DBUG_PRINT("info", ("Turning ON use of write instead of insert"));
4124 m_use_write= TRUE;
4126 break;
4127 case HA_EXTRA_WRITE_CANNOT_REPLACE:
4128 DBUG_PRINT("info", ("HA_EXTRA_WRITE_CANNOT_REPLACE"));
4129 DBUG_PRINT("info", ("Turning OFF use of write instead of insert"));
4130 m_use_write= FALSE;
4131 break;
4132 case HA_EXTRA_DELETE_CANNOT_BATCH:
4133 DBUG_PRINT("info", ("HA_EXTRA_DELETE_CANNOT_BATCH"));
4134 m_delete_cannot_batch= TRUE;
4135 break;
4136 case HA_EXTRA_UPDATE_CANNOT_BATCH:
4137 DBUG_PRINT("info", ("HA_EXTRA_UPDATE_CANNOT_BATCH"));
4138 m_update_cannot_batch= TRUE;
4139 break;
4140 default:
4141 break;
4144 DBUG_RETURN(0);
4148 int ha_ndbcluster::reset()
4150 DBUG_ENTER("ha_ndbcluster::reset");
4151 if (m_cond)
4153 m_cond->cond_clear();
4157 Regular partition pruning will set the bitmap appropriately.
4158 Some queries like ALTER TABLE doesn't use partition pruning and
4159 thus the 'used_partitions' bitmap needs to be initialized
4161 if (m_part_info)
4162 bitmap_set_all(&m_part_info->used_partitions);
4164 /* reset flags set by extra calls */
4165 m_ignore_dup_key= FALSE;
4166 m_use_write= FALSE;
4167 m_ignore_no_key= FALSE;
4168 m_delete_cannot_batch= FALSE;
4169 m_update_cannot_batch= FALSE;
4171 DBUG_RETURN(0);
4176 Start of an insert, remember number of rows to be inserted, it will
4177 be used in write_row and get_autoincrement to send an optimal number
4178 of rows in each roundtrip to the server.
4180 @param
4181 rows number of rows to insert, 0 if unknown
4184 void ha_ndbcluster::start_bulk_insert(ha_rows rows)
4186 int bytes, batch;
4187 const NDBTAB *tab= m_table;
4189 DBUG_ENTER("start_bulk_insert");
4190 DBUG_PRINT("enter", ("rows: %d", (int)rows));
4192 m_rows_inserted= (ha_rows) 0;
4193 if (!m_use_write && m_ignore_dup_key)
4196 compare if expression with that in write_row
4197 we have a situation where peek_indexed_rows() will be called
4198 so we cannot batch
4200 DBUG_PRINT("info", ("Batching turned off as duplicate key is "
4201 "ignored by using peek_row"));
4202 m_rows_to_insert= 1;
4203 m_bulk_insert_rows= 1;
4204 DBUG_VOID_RETURN;
4206 if (rows == (ha_rows) 0)
4208 /* We don't know how many will be inserted, guess */
4209 m_rows_to_insert= m_autoincrement_prefetch;
4211 else
4212 m_rows_to_insert= rows;
4215 Calculate how many rows that should be inserted
4216 per roundtrip to NDB. This is done in order to minimize the
4217 number of roundtrips as much as possible. However performance will
4218 degrade if too many bytes are inserted, thus it's limited by this
4219 calculation.
4221 const int bytesperbatch= 8192;
4222 bytes= 12 + tab->getRowSizeInBytes() + 4 * tab->getNoOfColumns();
4223 batch= bytesperbatch/bytes;
4224 batch= batch == 0 ? 1 : batch;
4225 DBUG_PRINT("info", ("batch: %d, bytes: %d", batch, bytes));
4226 m_bulk_insert_rows= batch;
4228 DBUG_VOID_RETURN;
4232 End of an insert.
4234 int ha_ndbcluster::end_bulk_insert()
4236 int error= 0;
4238 DBUG_ENTER("end_bulk_insert");
4239 // Check if last inserts need to be flushed
4240 if (m_bulk_insert_not_flushed)
4242 NdbTransaction *trans= m_active_trans;
4243 // Send rows to NDB
4244 DBUG_PRINT("info", ("Sending inserts to NDB, "\
4245 "rows_inserted: %d bulk_insert_rows: %d",
4246 (int) m_rows_inserted, (int) m_bulk_insert_rows));
4247 m_bulk_insert_not_flushed= FALSE;
4248 if (m_transaction_on)
4250 if (execute_no_commit(this, trans,FALSE) != 0)
4252 no_uncommitted_rows_execute_failure();
4253 my_errno= error= ndb_err(trans);
4256 else
4258 if (execute_commit(this, trans) != 0)
4260 no_uncommitted_rows_execute_failure();
4261 my_errno= error= ndb_err(trans);
4263 else
4265 IF_DBUG(int res=) trans->restart();
4266 DBUG_ASSERT(res == 0);
4271 m_rows_inserted= (ha_rows) 0;
4272 m_rows_to_insert= (ha_rows) 1;
4273 DBUG_RETURN(error);
4277 int ha_ndbcluster::extra_opt(enum ha_extra_function operation, ulong cache_size)
4279 DBUG_ENTER("extra_opt");
4280 DBUG_PRINT("enter", ("cache_size: %lu", cache_size));
4281 DBUG_RETURN(extra(operation));
4284 static const char *ha_ndbcluster_exts[] = {
4285 ha_ndb_ext,
4286 NullS
4289 const char** ha_ndbcluster::bas_ext() const
4291 return ha_ndbcluster_exts;
4295 How many seeks it will take to read through the table.
4297 This is to be comparable to the number returned by records_in_range so
4298 that we can decide if we should scan the table or use keys.
4301 double ha_ndbcluster::scan_time()
4303 DBUG_ENTER("ha_ndbcluster::scan_time()");
4304 double res= rows2double(stats.records*1000);
4305 DBUG_PRINT("exit", ("table: %s value: %f",
4306 m_tabname, res));
4307 DBUG_RETURN(res);
4311 Convert MySQL table locks into locks supported by Ndb Cluster.
4312 Note that MySQL Cluster does currently not support distributed
4313 table locks, so to be safe one should set cluster in Single
4314 User Mode, before relying on table locks when updating tables
4315 from several MySQL servers
4318 THR_LOCK_DATA **ha_ndbcluster::store_lock(THD *thd,
4319 THR_LOCK_DATA **to,
4320 enum thr_lock_type lock_type)
4322 DBUG_ENTER("store_lock");
4323 if (lock_type != TL_IGNORE && m_lock.type == TL_UNLOCK)
4326 /* If we are not doing a LOCK TABLE, then allow multiple
4327 writers */
4329 /* Since NDB does not currently have table locks
4330 this is treated as a ordinary lock */
4332 if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
4333 lock_type <= TL_WRITE) && !thd->in_lock_tables)
4334 lock_type= TL_WRITE_ALLOW_WRITE;
4336 /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
4337 MySQL would use the lock TL_READ_NO_INSERT on t2, and that
4338 would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
4339 to t2. Convert the lock to a normal read lock to allow
4340 concurrent inserts to t2. */
4342 if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables)
4343 lock_type= TL_READ;
4345 m_lock.type=lock_type;
4347 *to++= &m_lock;
4349 DBUG_PRINT("exit", ("lock_type: %d", lock_type));
4351 DBUG_RETURN(to);
4354 #ifndef DBUG_OFF
4355 #define PRINT_OPTION_FLAGS(t) { \
4356 if (t->options & OPTION_NOT_AUTOCOMMIT) \
4357 DBUG_PRINT("thd->options", ("OPTION_NOT_AUTOCOMMIT")); \
4358 if (t->options & OPTION_BEGIN) \
4359 DBUG_PRINT("thd->options", ("OPTION_BEGIN")); \
4360 if (t->options & OPTION_TABLE_LOCK) \
4361 DBUG_PRINT("thd->options", ("OPTION_TABLE_LOCK")); \
4363 #else
4364 #define PRINT_OPTION_FLAGS(t)
4365 #endif
4369 As MySQL will execute an external lock for every new table it uses
4370 we can use this to start the transactions.
4371 If we are in auto_commit mode we just need to start a transaction
4372 for the statement, this will be stored in thd_ndb.stmt.
4373 If not, we have to start a master transaction if there doesn't exist
4374 one from before, this will be stored in thd_ndb.all
4376 When a table lock is held one transaction will be started which holds
4377 the table lock and for each statement a hupp transaction will be started
4378 If we are locking the table then:
4379 - save the NdbDictionary::Table for easy access
4380 - save reference to table statistics
4381 - refresh list of the indexes for the table if needed (if altered)
4384 #ifdef HAVE_NDB_BINLOG
4385 extern Master_info *active_mi;
4386 static int ndbcluster_update_apply_status(THD *thd, int do_update)
4388 Thd_ndb *thd_ndb= get_thd_ndb(thd);
4389 Ndb *ndb= thd_ndb->ndb;
4390 NDBDICT *dict= ndb->getDictionary();
4391 const NDBTAB *ndbtab;
4392 NdbTransaction *trans= thd_ndb->trans;
4393 ndb->setDatabaseName(NDB_REP_DB);
4394 Ndb_table_guard ndbtab_g(dict, NDB_APPLY_TABLE);
4395 if (!(ndbtab= ndbtab_g.get_table()))
4397 return -1;
4399 NdbOperation *op= 0;
4400 int r= 0;
4401 r|= (op= trans->getNdbOperation(ndbtab)) == 0;
4402 DBUG_ASSERT(r == 0);
4403 if (do_update)
4404 r|= op->updateTuple();
4405 else
4406 r|= op->writeTuple();
4407 DBUG_ASSERT(r == 0);
4408 // server_id
4409 r|= op->equal(0u, (Uint32)thd->server_id);
4410 DBUG_ASSERT(r == 0);
4411 if (!do_update)
4413 // epoch
4414 r|= op->setValue(1u, (Uint64)0);
4415 DBUG_ASSERT(r == 0);
4417 // log_name
4418 char tmp_buf[FN_REFLEN];
4419 ndb_pack_varchar(ndbtab->getColumn(2u), tmp_buf,
4420 active_mi->rli.group_master_log_name,
4421 strlen(active_mi->rli.group_master_log_name));
4422 r|= op->setValue(2u, tmp_buf);
4423 DBUG_ASSERT(r == 0);
4424 // start_pos
4425 r|= op->setValue(3u, (Uint64)active_mi->rli.group_master_log_pos);
4426 DBUG_ASSERT(r == 0);
4427 // end_pos
4428 r|= op->setValue(4u, (Uint64)active_mi->rli.group_master_log_pos +
4429 ((Uint64)active_mi->rli.future_event_relay_log_pos -
4430 (Uint64)active_mi->rli.group_relay_log_pos));
4431 DBUG_ASSERT(r == 0);
4432 return 0;
4434 #endif /* HAVE_NDB_BINLOG */
4436 void ha_ndbcluster::transaction_checks(THD *thd)
4438 if (thd->lex->sql_command == SQLCOM_LOAD)
4440 m_transaction_on= FALSE;
4441 /* Would be simpler if has_transactions() didn't always say "yes" */
4442 thd->transaction.all.modified_non_trans_table=
4443 thd->transaction.stmt.modified_non_trans_table= TRUE;
4445 else if (!thd->transaction.on)
4446 m_transaction_on= FALSE;
4447 else
4448 m_transaction_on= thd->variables.ndb_use_transactions;
4451 int ha_ndbcluster::start_statement(THD *thd,
4452 Thd_ndb *thd_ndb,
4453 Ndb *ndb)
4455 DBUG_ENTER("ha_ndbcluster::start_statement");
4456 PRINT_OPTION_FLAGS(thd);
4458 trans_register_ha(thd, FALSE, ndbcluster_hton);
4459 if (!thd_ndb->trans)
4461 if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
4462 trans_register_ha(thd, TRUE, ndbcluster_hton);
4463 DBUG_PRINT("trans",("Starting transaction"));
4464 thd_ndb->trans= ndb->startTransaction();
4465 if (thd_ndb->trans == NULL)
4466 ERR_RETURN(ndb->getNdbError());
4467 thd_ndb->init_open_tables();
4468 thd_ndb->query_state&= NDB_QUERY_NORMAL;
4469 thd_ndb->trans_options= 0;
4470 thd_ndb->m_slow_path= FALSE;
4471 if (!(thd->options & OPTION_BIN_LOG) ||
4472 thd->variables.binlog_format == BINLOG_FORMAT_STMT)
4474 thd_ndb->trans_options|= TNTO_NO_LOGGING;
4475 thd_ndb->m_slow_path= TRUE;
4477 else if (thd->slave_thread)
4478 thd_ndb->m_slow_path= TRUE;
4481 If this is the start of a LOCK TABLE, a table look
4482 should be taken on the table in NDB
4484 Check if it should be read or write lock
4486 if (thd->options & (OPTION_TABLE_LOCK))
4488 //lockThisTable();
4489 DBUG_PRINT("info", ("Locking the table..." ));
4491 DBUG_RETURN(0);
4494 int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb)
4497 This is the place to make sure this handler instance
4498 has a started transaction.
4500 The transaction is started by the first handler on which
4501 MySQL Server calls external lock
4503 Other handlers in the same stmt or transaction should use
4504 the same NDB transaction. This is done by setting up the m_active_trans
4505 pointer to point to the NDB transaction.
4508 DBUG_ENTER("ha_ndbcluster::init_handler_for_statement");
4509 // store thread specific data first to set the right context
4510 m_force_send= thd->variables.ndb_force_send;
4511 m_ha_not_exact_count= !thd->variables.ndb_use_exact_count;
4512 m_autoincrement_prefetch=
4513 (thd->variables.ndb_autoincrement_prefetch_sz >
4514 NDB_DEFAULT_AUTO_PREFETCH) ?
4515 (ha_rows) thd->variables.ndb_autoincrement_prefetch_sz
4516 : (ha_rows) NDB_DEFAULT_AUTO_PREFETCH;
4517 m_active_trans= thd_ndb->trans;
4518 DBUG_ASSERT(m_active_trans);
4519 // Start of transaction
4520 m_rows_changed= 0;
4521 m_ops_pending= 0;
4522 m_slow_path= thd_ndb->m_slow_path;
4523 #ifdef HAVE_NDB_BINLOG
4524 if (unlikely(m_slow_path))
4526 if (m_share == ndb_apply_status_share && thd->slave_thread)
4527 thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS;
4529 #endif
4531 if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
4533 const void *key= m_table;
4534 HASH_SEARCH_STATE state;
4535 THD_NDB_SHARE *thd_ndb_share=
4536 (THD_NDB_SHARE*)hash_first(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state);
4537 while (thd_ndb_share && thd_ndb_share->key != key)
4538 thd_ndb_share= (THD_NDB_SHARE*)hash_next(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state);
4539 if (thd_ndb_share == 0)
4541 thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root,
4542 sizeof(THD_NDB_SHARE));
4543 if (!thd_ndb_share)
4545 mem_alloc_error(sizeof(THD_NDB_SHARE));
4546 DBUG_RETURN(1);
4548 thd_ndb_share->key= key;
4549 thd_ndb_share->stat.last_count= thd_ndb->count;
4550 thd_ndb_share->stat.no_uncommitted_rows_count= 0;
4551 thd_ndb_share->stat.records= ~(ha_rows)0;
4552 my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share);
4554 else if (thd_ndb_share->stat.last_count != thd_ndb->count)
4556 thd_ndb_share->stat.last_count= thd_ndb->count;
4557 thd_ndb_share->stat.no_uncommitted_rows_count= 0;
4558 thd_ndb_share->stat.records= ~(ha_rows)0;
4560 DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx",
4561 (long) thd_ndb_share, (long) key));
4562 m_table_info= &thd_ndb_share->stat;
4564 else
4566 struct Ndb_local_table_statistics &stat= m_table_info_instance;
4567 stat.last_count= thd_ndb->count;
4568 stat.no_uncommitted_rows_count= 0;
4569 stat.records= ~(ha_rows)0;
4570 m_table_info= &stat;
4572 DBUG_RETURN(0);
4575 int ha_ndbcluster::external_lock(THD *thd, int lock_type)
4577 int error=0;
4578 DBUG_ENTER("external_lock");
4581 Check that this handler instance has a connection
4582 set up to the Ndb object of thd
4584 if (check_ndb_connection(thd))
4585 DBUG_RETURN(1);
4587 Thd_ndb *thd_ndb= get_thd_ndb(thd);
4588 Ndb *ndb= thd_ndb->ndb;
4590 DBUG_PRINT("enter", ("this: 0x%lx thd: 0x%lx thd_ndb: %lx "
4591 "thd_ndb->lock_count: %d",
4592 (long) this, (long) thd, (long) thd_ndb,
4593 thd_ndb->lock_count));
4595 if (lock_type != F_UNLCK)
4597 DBUG_PRINT("info", ("lock_type != F_UNLCK"));
4598 transaction_checks(thd);
4599 if (!thd_ndb->lock_count++)
4601 if ((error= start_statement(thd, thd_ndb, ndb)))
4602 goto error;
4604 if ((error= init_handler_for_statement(thd, thd_ndb)))
4605 goto error;
4606 DBUG_RETURN(0);
4608 else
4610 DBUG_PRINT("info", ("lock_type == F_UNLCK"));
4612 if (ndb_cache_check_time && m_rows_changed)
4614 DBUG_PRINT("info", ("Rows has changed and util thread is running"));
4615 if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
4617 DBUG_PRINT("info", ("Add share to list of tables to be invalidated"));
4618 /* NOTE push_back allocates memory using transactions mem_root! */
4619 thd_ndb->changed_tables.push_back(m_share, &thd->transaction.mem_root);
4622 pthread_mutex_lock(&m_share->mutex);
4623 DBUG_PRINT("info", ("Invalidating commit_count"));
4624 m_share->commit_count= 0;
4625 m_share->commit_count_lock++;
4626 pthread_mutex_unlock(&m_share->mutex);
4629 if (!--thd_ndb->lock_count)
4631 DBUG_PRINT("trans", ("Last external_lock"));
4632 PRINT_OPTION_FLAGS(thd);
4634 if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
4636 if (thd_ndb->trans)
4639 Unlock is done without a transaction commit / rollback.
4640 This happens if the thread didn't update any rows
4641 We must in this case close the transaction to release resources
4643 DBUG_PRINT("trans",("ending non-updating transaction"));
4644 ndb->closeTransaction(thd_ndb->trans);
4645 thd_ndb->trans= NULL;
4649 m_table_info= NULL;
4652 This is the place to make sure this handler instance
4653 no longer are connected to the active transaction.
4655 And since the handler is no longer part of the transaction
4656 it can't have open cursors, ops or blobs pending.
4658 m_active_trans= NULL;
4660 if (m_active_cursor)
4661 DBUG_PRINT("warning", ("m_active_cursor != NULL"));
4662 m_active_cursor= NULL;
4664 if (m_multi_cursor)
4665 DBUG_PRINT("warning", ("m_multi_cursor != NULL"));
4666 m_multi_cursor= NULL;
4668 if (m_blobs_pending)
4669 DBUG_PRINT("warning", ("blobs_pending != 0"));
4670 m_blobs_pending= 0;
4672 if (m_ops_pending)
4673 DBUG_PRINT("warning", ("ops_pending != 0L"));
4674 m_ops_pending= 0;
4675 DBUG_RETURN(0);
4677 error:
4678 thd_ndb->lock_count--;
4679 DBUG_RETURN(error);
4683 Unlock the last row read in an open scan.
4684 Rows are unlocked by default in ndb, but
4685 for SELECT FOR UPDATE and SELECT LOCK WIT SHARE MODE
4686 locks are kept if unlock_row() is not called.
4689 void ha_ndbcluster::unlock_row()
4691 DBUG_ENTER("unlock_row");
4693 DBUG_PRINT("info", ("Unlocking row"));
4694 m_lock_tuple= FALSE;
4695 DBUG_VOID_RETURN;
4699 Start a transaction for running a statement if one is not
4700 already running in a transaction. This will be the case in
4701 a BEGIN; COMMIT; block
4702 When using LOCK TABLE's external_lock will start a transaction
4703 since ndb does not currently does not support table locking.
4706 int ha_ndbcluster::start_stmt(THD *thd, thr_lock_type lock_type)
4708 int error=0;
4709 DBUG_ENTER("start_stmt");
4711 Thd_ndb *thd_ndb= get_thd_ndb(thd);
4712 transaction_checks(thd);
4713 if (!thd_ndb->start_stmt_count++)
4715 Ndb *ndb= thd_ndb->ndb;
4716 if ((error= start_statement(thd, thd_ndb, ndb)))
4717 goto error;
4719 if ((error= init_handler_for_statement(thd, thd_ndb)))
4720 goto error;
4721 DBUG_RETURN(0);
4722 error:
4723 thd_ndb->start_stmt_count--;
4724 DBUG_RETURN(error);
4729 Commit a transaction started in NDB.
4732 static int ndbcluster_commit(handlerton *hton, THD *thd, bool all)
4734 int res= 0;
4735 Thd_ndb *thd_ndb= get_thd_ndb(thd);
4736 Ndb *ndb= thd_ndb->ndb;
4737 NdbTransaction *trans= thd_ndb->trans;
4739 DBUG_ENTER("ndbcluster_commit");
4740 DBUG_ASSERT(ndb);
4741 PRINT_OPTION_FLAGS(thd);
4742 DBUG_PRINT("enter", ("Commit %s", (all ? "all" : "stmt")));
4743 thd_ndb->start_stmt_count= 0;
4744 if (trans == NULL || (!all &&
4745 thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
4748 An odditity in the handler interface is that commit on handlerton
4749 is called to indicate end of statement only in cases where
4750 autocommit isn't used and the all flag isn't set.
4752 We also leave quickly when a transaction haven't even been started,
4753 in this case we are safe that no clean up is needed. In this case
4754 the MySQL Server could handle the query without contacting the
4755 NDB kernel.
4757 DBUG_PRINT("info", ("Commit before start or end-of-statement only"));
4758 DBUG_RETURN(0);
4761 #ifdef HAVE_NDB_BINLOG
4762 if (unlikely(thd_ndb->m_slow_path))
4764 if (thd->slave_thread)
4765 ndbcluster_update_apply_status
4766 (thd, thd_ndb->trans_options & TNTO_INJECTED_APPLY_STATUS);
4768 #endif /* HAVE_NDB_BINLOG */
4770 if (execute_commit(thd,trans) != 0)
4772 const NdbError err= trans->getNdbError();
4773 const NdbOperation *error_op= trans->getNdbErrorOperation();
4774 set_ndb_err(thd, err);
4775 res= ndb_to_mysql_error(&err);
4776 if (res != -1)
4777 ndbcluster_print_error(res, error_op);
4779 ndb->closeTransaction(trans);
4780 thd_ndb->trans= NULL;
4782 /* Clear commit_count for tables changed by transaction */
4783 NDB_SHARE* share;
4784 List_iterator_fast<NDB_SHARE> it(thd_ndb->changed_tables);
4785 while ((share= it++))
4787 pthread_mutex_lock(&share->mutex);
4788 DBUG_PRINT("info", ("Invalidate commit_count for %s, share->commit_count: %lu",
4789 share->table_name, (ulong) share->commit_count));
4790 share->commit_count= 0;
4791 share->commit_count_lock++;
4792 pthread_mutex_unlock(&share->mutex);
4794 thd_ndb->changed_tables.empty();
4796 DBUG_RETURN(res);
4801 Rollback a transaction started in NDB.
4804 static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all)
4806 int res= 0;
4807 Thd_ndb *thd_ndb= get_thd_ndb(thd);
4808 Ndb *ndb= thd_ndb->ndb;
4809 NdbTransaction *trans= thd_ndb->trans;
4811 DBUG_ENTER("ndbcluster_rollback");
4812 DBUG_ASSERT(ndb);
4813 thd_ndb->start_stmt_count= 0;
4814 if (trans == NULL || (!all &&
4815 thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
4817 /* Ignore end-of-statement until real rollback or commit is called */
4818 DBUG_PRINT("info", ("Rollback before start or end-of-statement only"));
4819 DBUG_RETURN(0);
4822 if (trans->execute(NdbTransaction::Rollback) != 0)
4824 const NdbError err= trans->getNdbError();
4825 const NdbOperation *error_op= trans->getNdbErrorOperation();
4826 set_ndb_err(thd, err);
4827 res= ndb_to_mysql_error(&err);
4828 if (res != -1)
4829 ndbcluster_print_error(res, error_op);
4831 ndb->closeTransaction(trans);
4832 thd_ndb->trans= NULL;
4834 /* Clear list of tables changed by transaction */
4835 thd_ndb->changed_tables.empty();
4837 DBUG_RETURN(res);
4842 Define NDB column based on Field.
4844 Not member of ha_ndbcluster because NDBCOL cannot be declared.
4846 MySQL text types with character set "binary" are mapped to true
4847 NDB binary types without a character set. This may change.
4849 @return
4850 Returns 0 or mysql error code.
4853 static int create_ndb_column(NDBCOL &col,
4854 Field *field,
4855 HA_CREATE_INFO *info)
4857 // Set name
4858 if (col.setName(field->field_name))
4860 return (my_errno= errno);
4862 // Get char set
4863 CHARSET_INFO *cs= field->charset();
4864 // Set type and sizes
4865 const enum enum_field_types mysql_type= field->real_type();
4866 switch (mysql_type) {
4867 // Numeric types
4868 case MYSQL_TYPE_TINY:
4869 if (field->flags & UNSIGNED_FLAG)
4870 col.setType(NDBCOL::Tinyunsigned);
4871 else
4872 col.setType(NDBCOL::Tinyint);
4873 col.setLength(1);
4874 break;
4875 case MYSQL_TYPE_SHORT:
4876 if (field->flags & UNSIGNED_FLAG)
4877 col.setType(NDBCOL::Smallunsigned);
4878 else
4879 col.setType(NDBCOL::Smallint);
4880 col.setLength(1);
4881 break;
4882 case MYSQL_TYPE_LONG:
4883 if (field->flags & UNSIGNED_FLAG)
4884 col.setType(NDBCOL::Unsigned);
4885 else
4886 col.setType(NDBCOL::Int);
4887 col.setLength(1);
4888 break;
4889 case MYSQL_TYPE_INT24:
4890 if (field->flags & UNSIGNED_FLAG)
4891 col.setType(NDBCOL::Mediumunsigned);
4892 else
4893 col.setType(NDBCOL::Mediumint);
4894 col.setLength(1);
4895 break;
4896 case MYSQL_TYPE_LONGLONG:
4897 if (field->flags & UNSIGNED_FLAG)
4898 col.setType(NDBCOL::Bigunsigned);
4899 else
4900 col.setType(NDBCOL::Bigint);
4901 col.setLength(1);
4902 break;
4903 case MYSQL_TYPE_FLOAT:
4904 col.setType(NDBCOL::Float);
4905 col.setLength(1);
4906 break;
4907 case MYSQL_TYPE_DOUBLE:
4908 col.setType(NDBCOL::Double);
4909 col.setLength(1);
4910 break;
4911 case MYSQL_TYPE_DECIMAL:
4913 Field_decimal *f= (Field_decimal*)field;
4914 uint precision= f->pack_length();
4915 uint scale= f->decimals();
4916 if (field->flags & UNSIGNED_FLAG)
4918 col.setType(NDBCOL::Olddecimalunsigned);
4919 precision-= (scale > 0);
4921 else
4923 col.setType(NDBCOL::Olddecimal);
4924 precision-= 1 + (scale > 0);
4926 col.setPrecision(precision);
4927 col.setScale(scale);
4928 col.setLength(1);
4930 break;
4931 case MYSQL_TYPE_NEWDECIMAL:
4933 Field_new_decimal *f= (Field_new_decimal*)field;
4934 uint precision= f->precision;
4935 uint scale= f->decimals();
4936 if (field->flags & UNSIGNED_FLAG)
4938 col.setType(NDBCOL::Decimalunsigned);
4940 else
4942 col.setType(NDBCOL::Decimal);
4944 col.setPrecision(precision);
4945 col.setScale(scale);
4946 col.setLength(1);
4948 break;
4949 // Date types
4950 case MYSQL_TYPE_DATETIME:
4951 col.setType(NDBCOL::Datetime);
4952 col.setLength(1);
4953 break;
4954 case MYSQL_TYPE_DATE: // ?
4955 col.setType(NDBCOL::Char);
4956 col.setLength(field->pack_length());
4957 break;
4958 case MYSQL_TYPE_NEWDATE:
4959 col.setType(NDBCOL::Date);
4960 col.setLength(1);
4961 break;
4962 case MYSQL_TYPE_TIME:
4963 col.setType(NDBCOL::Time);
4964 col.setLength(1);
4965 break;
4966 case MYSQL_TYPE_YEAR:
4967 col.setType(NDBCOL::Year);
4968 col.setLength(1);
4969 break;
4970 case MYSQL_TYPE_TIMESTAMP:
4971 col.setType(NDBCOL::Timestamp);
4972 col.setLength(1);
4973 break;
4974 // Char types
4975 case MYSQL_TYPE_STRING:
4976 if (field->pack_length() == 0)
4978 col.setType(NDBCOL::Bit);
4979 col.setLength(1);
4981 else if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
4983 col.setType(NDBCOL::Binary);
4984 col.setLength(field->pack_length());
4986 else
4988 col.setType(NDBCOL::Char);
4989 col.setCharset(cs);
4990 col.setLength(field->pack_length());
4992 break;
4993 case MYSQL_TYPE_VAR_STRING: // ?
4994 case MYSQL_TYPE_VARCHAR:
4996 Field_varstring* f= (Field_varstring*)field;
4997 if (f->length_bytes == 1)
4999 if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
5000 col.setType(NDBCOL::Varbinary);
5001 else {
5002 col.setType(NDBCOL::Varchar);
5003 col.setCharset(cs);
5006 else if (f->length_bytes == 2)
5008 if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
5009 col.setType(NDBCOL::Longvarbinary);
5010 else {
5011 col.setType(NDBCOL::Longvarchar);
5012 col.setCharset(cs);
5015 else
5017 return HA_ERR_UNSUPPORTED;
5019 col.setLength(field->field_length);
5021 break;
5022 // Blob types (all come in as MYSQL_TYPE_BLOB)
5023 mysql_type_tiny_blob:
5024 case MYSQL_TYPE_TINY_BLOB:
5025 if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
5026 col.setType(NDBCOL::Blob);
5027 else {
5028 col.setType(NDBCOL::Text);
5029 col.setCharset(cs);
5031 col.setInlineSize(256);
5032 // No parts
5033 col.setPartSize(0);
5034 col.setStripeSize(0);
5035 break;
5036 //mysql_type_blob:
5037 case MYSQL_TYPE_GEOMETRY:
5038 case MYSQL_TYPE_BLOB:
5039 if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
5040 col.setType(NDBCOL::Blob);
5041 else {
5042 col.setType(NDBCOL::Text);
5043 col.setCharset(cs);
5046 Field_blob *field_blob= (Field_blob *)field;
5048 * max_data_length is 2^8-1, 2^16-1, 2^24-1 for tiny, blob, medium.
5049 * Tinyblob gets no blob parts. The other cases are just a crude
5050 * way to control part size and striping.
5052 * In mysql blob(256) is promoted to blob(65535) so it does not
5053 * in fact fit "inline" in NDB.
5055 if (field_blob->max_data_length() < (1 << 8))
5056 goto mysql_type_tiny_blob;
5057 else if (field_blob->max_data_length() < (1 << 16))
5059 col.setInlineSize(256);
5060 col.setPartSize(2000);
5061 col.setStripeSize(16);
5063 else if (field_blob->max_data_length() < (1 << 24))
5064 goto mysql_type_medium_blob;
5065 else
5066 goto mysql_type_long_blob;
5068 break;
5069 mysql_type_medium_blob:
5070 case MYSQL_TYPE_MEDIUM_BLOB:
5071 if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
5072 col.setType(NDBCOL::Blob);
5073 else {
5074 col.setType(NDBCOL::Text);
5075 col.setCharset(cs);
5077 col.setInlineSize(256);
5078 col.setPartSize(4000);
5079 col.setStripeSize(8);
5080 break;
5081 mysql_type_long_blob:
5082 case MYSQL_TYPE_LONG_BLOB:
5083 if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin)
5084 col.setType(NDBCOL::Blob);
5085 else {
5086 col.setType(NDBCOL::Text);
5087 col.setCharset(cs);
5089 col.setInlineSize(256);
5090 col.setPartSize(8000);
5091 col.setStripeSize(4);
5092 break;
5093 // Other types
5094 case MYSQL_TYPE_ENUM:
5095 col.setType(NDBCOL::Char);
5096 col.setLength(field->pack_length());
5097 break;
5098 case MYSQL_TYPE_SET:
5099 col.setType(NDBCOL::Char);
5100 col.setLength(field->pack_length());
5101 break;
5102 case MYSQL_TYPE_BIT:
5104 int no_of_bits= field->field_length;
5105 col.setType(NDBCOL::Bit);
5106 if (!no_of_bits)
5107 col.setLength(1);
5108 else
5109 col.setLength(no_of_bits);
5110 break;
5112 case MYSQL_TYPE_NULL:
5113 goto mysql_type_unsupported;
5114 mysql_type_unsupported:
5115 default:
5116 return HA_ERR_UNSUPPORTED;
5118 // Set nullable and pk
5119 col.setNullable(field->maybe_null());
5120 col.setPrimaryKey(field->flags & PRI_KEY_FLAG);
5121 // Set autoincrement
5122 if (field->flags & AUTO_INCREMENT_FLAG)
5124 #ifndef DBUG_OFF
5125 char buff[22];
5126 #endif
5127 col.setAutoIncrement(TRUE);
5128 ulonglong value= info->auto_increment_value ?
5129 info->auto_increment_value : (ulonglong) 1;
5130 DBUG_PRINT("info", ("Autoincrement key, initial: %s", llstr(value, buff)));
5131 col.setAutoIncrementInitialValue(value);
5133 else
5134 col.setAutoIncrement(FALSE);
5135 return 0;
5139 Create a table in NDB Cluster
5142 int ha_ndbcluster::create(const char *name,
5143 TABLE *form,
5144 HA_CREATE_INFO *create_info)
5146 THD *thd= current_thd;
5147 NDBTAB tab;
5148 NDBCOL col;
5149 size_t pack_length, length;
5150 uint i, pk_length= 0;
5151 uchar *data= NULL, *pack_data= NULL;
5152 bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
5153 bool is_truncate= (thd->lex->sql_command == SQLCOM_TRUNCATE);
5154 char tablespace[FN_LEN + 1];
5155 NdbDictionary::Table::SingleUserMode single_user_mode= NdbDictionary::Table::SingleUserModeLocked;
5157 DBUG_ENTER("ha_ndbcluster::create");
5158 DBUG_PRINT("enter", ("name: %s", name));
5160 DBUG_ASSERT(*fn_rext((char*)name) == 0);
5161 set_dbname(name);
5162 set_tabname(name);
5164 if ((my_errno= check_ndb_connection()))
5165 DBUG_RETURN(my_errno);
5167 Ndb *ndb= get_ndb();
5168 NDBDICT *dict= ndb->getDictionary();
5170 if (is_truncate)
5173 Ndb_table_guard ndbtab_g(dict, m_tabname);
5174 if (!(m_table= ndbtab_g.get_table()))
5175 ERR_RETURN(dict->getNdbError());
5176 if ((get_tablespace_name(thd, tablespace, FN_LEN)))
5177 create_info->tablespace= tablespace;
5178 m_table= NULL;
5180 DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE"));
5181 if ((my_errno= delete_table(name)))
5182 DBUG_RETURN(my_errno);
5184 table= form;
5185 if (create_from_engine)
5188 Table already exists in NDB and frm file has been created by
5189 caller.
5190 Do Ndb specific stuff, such as create a .ndb file
5192 if ((my_errno= write_ndb_file(name)))
5193 DBUG_RETURN(my_errno);
5194 #ifdef HAVE_NDB_BINLOG
5195 ndbcluster_create_binlog_setup(get_ndb(), name, strlen(name),
5196 m_dbname, m_tabname, FALSE);
5197 #endif /* HAVE_NDB_BINLOG */
5198 DBUG_RETURN(my_errno);
5201 #ifdef HAVE_NDB_BINLOG
5203 Don't allow table creation unless
5204 schema distribution table is setup
5205 ( unless it is a creation of the schema dist table itself )
5207 if (!ndb_schema_share)
5209 if (!(strcmp(m_dbname, NDB_REP_DB) == 0 &&
5210 strcmp(m_tabname, NDB_SCHEMA_TABLE) == 0))
5212 DBUG_PRINT("info", ("Schema distribution table not setup"));
5213 DBUG_ASSERT(ndb_schema_share);
5214 DBUG_RETURN(HA_ERR_NO_CONNECTION);
5216 single_user_mode = NdbDictionary::Table::SingleUserModeReadWrite;
5218 #endif /* HAVE_NDB_BINLOG */
5220 DBUG_PRINT("table", ("name: %s", m_tabname));
5221 if (tab.setName(m_tabname))
5223 DBUG_RETURN(my_errno= errno);
5225 tab.setLogging(!(create_info->options & HA_LEX_CREATE_TMP_TABLE));
5226 tab.setSingleUserMode(single_user_mode);
5228 // Save frm data for this table
5229 if (readfrm(name, &data, &length))
5230 DBUG_RETURN(1);
5231 if (packfrm(data, length, &pack_data, &pack_length))
5233 my_free((char*)data, MYF(0));
5234 DBUG_RETURN(2);
5236 DBUG_PRINT("info",
5237 ("setFrm data: 0x%lx len: %lu", (long) pack_data,
5238 (ulong) pack_length));
5239 tab.setFrm(pack_data, pack_length);
5240 my_free((char*)data, MYF(0));
5241 my_free((char*)pack_data, MYF(0));
5244 Check for disk options
5246 if (create_info->storage_media == HA_SM_DISK)
5248 if (create_info->tablespace)
5249 tab.setTablespaceName(create_info->tablespace);
5250 else
5251 tab.setTablespaceName("DEFAULT-TS");
5253 else if (create_info->tablespace)
5255 if (create_info->storage_media == HA_SM_MEMORY)
5257 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
5258 ER_ILLEGAL_HA_CREATE_OPTION,
5259 ER(ER_ILLEGAL_HA_CREATE_OPTION),
5260 ndbcluster_hton_name,
5261 "TABLESPACE currently only supported for "
5262 "STORAGE DISK");
5263 DBUG_RETURN(HA_ERR_UNSUPPORTED);
5265 tab.setTablespaceName(create_info->tablespace);
5266 create_info->storage_media = HA_SM_DISK; //if use tablespace, that also means store on disk
5270 Handle table row type
5272 Default is to let table rows have var part reference so that online
5273 add column can be performed in the future. Explicitly setting row
5274 type to fixed will omit var part reference, which will save data
5275 memory in ndb, but at the cost of not being able to online add
5276 column to this table
5278 switch (create_info->row_type) {
5279 case ROW_TYPE_FIXED:
5280 tab.setForceVarPart(FALSE);
5281 break;
5282 case ROW_TYPE_DYNAMIC:
5283 /* fall through, treat as default */
5284 default:
5285 /* fall through, treat as default */
5286 case ROW_TYPE_DEFAULT:
5287 tab.setForceVarPart(TRUE);
5288 break;
5292 Setup columns
5294 for (i= 0; i < form->s->fields; i++)
5296 Field *field= form->field[i];
5297 DBUG_PRINT("info", ("name: %s type: %u pack_length: %d",
5298 field->field_name, field->real_type(),
5299 field->pack_length()));
5300 if ((my_errno= create_ndb_column(col, field, create_info)))
5301 DBUG_RETURN(my_errno);
5303 if (create_info->storage_media == HA_SM_DISK)
5304 col.setStorageType(NdbDictionary::Column::StorageTypeDisk);
5305 else
5306 col.setStorageType(NdbDictionary::Column::StorageTypeMemory);
5308 switch (create_info->row_type) {
5309 case ROW_TYPE_FIXED:
5310 if (field_type_forces_var_part(field->type()))
5312 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
5313 ER_ILLEGAL_HA_CREATE_OPTION,
5314 ER(ER_ILLEGAL_HA_CREATE_OPTION),
5315 ndbcluster_hton_name,
5316 "Row format FIXED incompatible with "
5317 "variable sized attribute");
5318 DBUG_RETURN(HA_ERR_UNSUPPORTED);
5320 break;
5321 case ROW_TYPE_DYNAMIC:
5323 Future: make columns dynamic in this case
5325 break;
5326 default:
5327 break;
5329 if (tab.addColumn(col))
5331 DBUG_RETURN(my_errno= errno);
5333 if (col.getPrimaryKey())
5334 pk_length += (field->pack_length() + 3) / 4;
5337 KEY* key_info;
5338 for (i= 0, key_info= form->key_info; i < form->s->keys; i++, key_info++)
5340 KEY_PART_INFO *key_part= key_info->key_part;
5341 KEY_PART_INFO *end= key_part + key_info->key_parts;
5342 for (; key_part != end; key_part++)
5343 tab.getColumn(key_part->fieldnr-1)->setStorageType(
5344 NdbDictionary::Column::StorageTypeMemory);
5347 // No primary key, create shadow key as 64 bit, auto increment
5348 if (form->s->primary_key == MAX_KEY)
5350 DBUG_PRINT("info", ("Generating shadow key"));
5351 if (col.setName("$PK"))
5353 DBUG_RETURN(my_errno= errno);
5355 col.setType(NdbDictionary::Column::Bigunsigned);
5356 col.setLength(1);
5357 col.setNullable(FALSE);
5358 col.setPrimaryKey(TRUE);
5359 col.setAutoIncrement(TRUE);
5360 if (tab.addColumn(col))
5362 DBUG_RETURN(my_errno= errno);
5364 pk_length += 2;
5367 // Make sure that blob tables don't have to big part size
5368 for (i= 0; i < form->s->fields; i++)
5371 * The extra +7 concists
5372 * 2 - words from pk in blob table
5373 * 5 - from extra words added by tup/dict??
5375 switch (form->field[i]->real_type()) {
5376 case MYSQL_TYPE_GEOMETRY:
5377 case MYSQL_TYPE_BLOB:
5378 case MYSQL_TYPE_MEDIUM_BLOB:
5379 case MYSQL_TYPE_LONG_BLOB:
5381 NdbDictionary::Column * column= tab.getColumn(i);
5382 int size= pk_length + (column->getPartSize()+3)/4 + 7;
5383 if (size > NDB_MAX_TUPLE_SIZE_IN_WORDS &&
5384 (pk_length+7) < NDB_MAX_TUPLE_SIZE_IN_WORDS)
5386 size= NDB_MAX_TUPLE_SIZE_IN_WORDS - pk_length - 7;
5387 column->setPartSize(4*size);
5390 * If size > NDB_MAX and pk_length+7 >= NDB_MAX
5391 * then the table can't be created anyway, so skip
5392 * changing part size, and have error later
5395 default:
5396 break;
5400 // Check partition info
5401 partition_info *part_info= form->part_info;
5402 if ((my_errno= set_up_partition_info(part_info, form, (void*)&tab)))
5404 DBUG_RETURN(my_errno);
5407 // Create the table in NDB
5408 if (dict->createTable(tab) != 0)
5410 const NdbError err= dict->getNdbError();
5411 set_ndb_err(thd, err);
5412 my_errno= ndb_to_mysql_error(&err);
5413 DBUG_RETURN(my_errno);
5416 Ndb_table_guard ndbtab_g(dict, m_tabname);
5417 // temporary set m_table during create
5418 // reset at return
5419 m_table= ndbtab_g.get_table();
5420 // TODO check also that we have the same frm...
5421 if (!m_table)
5423 /* purecov: begin deadcode */
5424 const NdbError err= dict->getNdbError();
5425 set_ndb_err(thd, err);
5426 my_errno= ndb_to_mysql_error(&err);
5427 DBUG_RETURN(my_errno);
5428 /* purecov: end */
5431 DBUG_PRINT("info", ("Table %s/%s created successfully",
5432 m_dbname, m_tabname));
5434 // Create secondary indexes
5435 my_errno= create_indexes(ndb, form);
5437 if (!my_errno)
5438 my_errno= write_ndb_file(name);
5439 else
5442 Failed to create an index,
5443 drop the table (and all it's indexes)
5445 while (dict->dropTableGlobal(*m_table))
5447 switch (dict->getNdbError().status)
5449 case NdbError::TemporaryError:
5450 if (!thd->killed)
5451 continue; // retry indefinitly
5452 break;
5453 default:
5454 break;
5456 break;
5458 m_table = 0;
5459 DBUG_RETURN(my_errno);
5462 #ifdef HAVE_NDB_BINLOG
5463 if (!my_errno)
5465 NDB_SHARE *share= 0;
5466 pthread_mutex_lock(&ndbcluster_mutex);
5468 First make sure we get a "fresh" share here, not an old trailing one...
5471 uint length= (uint) strlen(name);
5472 if ((share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
5473 (uchar*) name, length)))
5474 handle_trailing_share(share);
5477 get a new share
5480 /* ndb_share reference create */
5481 if (!(share= get_share(name, form, TRUE, TRUE)))
5483 sql_print_error("NDB: allocating table share for %s failed", name);
5484 /* my_errno is set */
5486 else
5488 DBUG_PRINT("NDB_SHARE", ("%s binlog create use_count: %u",
5489 share->key, share->use_count));
5491 pthread_mutex_unlock(&ndbcluster_mutex);
5493 while (!IS_TMP_PREFIX(m_tabname))
5495 String event_name(INJECTOR_EVENT_LEN);
5496 ndb_rep_event_name(&event_name,m_dbname,m_tabname);
5497 int do_event_op= ndb_binlog_running;
5499 if (!ndb_schema_share &&
5500 strcmp(share->db, NDB_REP_DB) == 0 &&
5501 strcmp(share->table_name, NDB_SCHEMA_TABLE) == 0)
5502 do_event_op= 1;
5505 Always create an event for the table, as other mysql servers
5506 expect it to be there.
5508 if (!ndbcluster_create_event(ndb, m_table, event_name.c_ptr(), share,
5509 share && do_event_op ? 2 : 1/* push warning */))
5511 if (ndb_extra_logging)
5512 sql_print_information("NDB Binlog: CREATE TABLE Event: %s",
5513 event_name.c_ptr());
5514 if (share &&
5515 ndbcluster_create_event_ops(share, m_table, event_name.c_ptr()))
5517 sql_print_error("NDB Binlog: FAILED CREATE TABLE event operations."
5518 " Event: %s", name);
5519 /* a warning has been issued to the client */
5523 warning has been issued if ndbcluster_create_event failed
5524 and (share && do_event_op)
5526 if (share && !do_event_op)
5527 share->flags|= NSF_NO_BINLOG;
5528 ndbcluster_log_schema_op(thd, share,
5529 thd->query(), thd->query_length(),
5530 share->db, share->table_name,
5531 m_table->getObjectId(),
5532 m_table->getObjectVersion(),
5533 (is_truncate) ?
5534 SOT_TRUNCATE_TABLE : SOT_CREATE_TABLE,
5535 0, 0, 1);
5536 break;
5539 #endif /* HAVE_NDB_BINLOG */
5541 m_table= 0;
5542 DBUG_RETURN(my_errno);
5545 int ha_ndbcluster::create_handler_files(const char *file,
5546 const char *old_name,
5547 int action_flag,
5548 HA_CREATE_INFO *create_info)
5550 Ndb* ndb;
5551 const NDBTAB *tab;
5552 uchar *data= NULL, *pack_data= NULL;
5553 size_t length, pack_length;
5554 int error= 0;
5556 DBUG_ENTER("create_handler_files");
5558 if (action_flag != CHF_INDEX_FLAG)
5560 DBUG_RETURN(FALSE);
5562 DBUG_PRINT("enter", ("file: %s", file));
5563 if (!(ndb= get_ndb()))
5564 DBUG_RETURN(HA_ERR_NO_CONNECTION);
5566 NDBDICT *dict= ndb->getDictionary();
5567 if (!create_info->frm_only)
5568 DBUG_RETURN(0); // Must be a create, ignore since frm is saved in create
5570 // TODO handle this
5571 DBUG_ASSERT(m_table != 0);
5573 set_dbname(file);
5574 set_tabname(file);
5575 Ndb_table_guard ndbtab_g(dict, m_tabname);
5576 DBUG_PRINT("info", ("m_dbname: %s, m_tabname: %s", m_dbname, m_tabname));
5577 if (!(tab= ndbtab_g.get_table()))
5578 DBUG_RETURN(0); // Unkown table, must be temporary table
5580 DBUG_ASSERT(get_ndb_share_state(m_share) == NSS_ALTERED);
5581 if (readfrm(file, &data, &length) ||
5582 packfrm(data, length, &pack_data, &pack_length))
5584 DBUG_PRINT("info", ("Missing frm for %s", m_tabname));
5585 my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
5586 my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
5587 error= 1;
5589 else
5591 DBUG_PRINT("info", ("Table %s has changed, altering frm in ndb",
5592 m_tabname));
5593 NdbDictionary::Table new_tab= *tab;
5594 new_tab.setFrm(pack_data, pack_length);
5595 if (dict->alterTableGlobal(*tab, new_tab))
5597 set_ndb_err(current_thd, dict->getNdbError());
5598 error= ndb_to_mysql_error(&dict->getNdbError());
5600 my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
5601 my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR));
5604 set_ndb_share_state(m_share, NSS_INITIAL);
5605 /* ndb_share reference schema(?) free */
5606 DBUG_PRINT("NDB_SHARE", ("%s binlog schema(?) free use_count: %u",
5607 m_share->key, m_share->use_count));
5608 free_share(&m_share); // Decrease ref_count
5610 DBUG_RETURN(error);
5613 int ha_ndbcluster::create_index(const char *name, KEY *key_info,
5614 NDB_INDEX_TYPE idx_type, uint idx_no)
5616 int error= 0;
5617 char unique_name[FN_LEN + 1];
5618 static const char* unique_suffix= "$unique";
5619 DBUG_ENTER("ha_ndbcluster::create_ordered_index");
5620 DBUG_PRINT("info", ("Creating index %u: %s", idx_no, name));
5622 if (idx_type == UNIQUE_ORDERED_INDEX || idx_type == UNIQUE_INDEX)
5624 strxnmov(unique_name, FN_LEN, name, unique_suffix, NullS);
5625 DBUG_PRINT("info", ("Created unique index name \'%s\' for index %d",
5626 unique_name, idx_no));
5629 switch (idx_type){
5630 case PRIMARY_KEY_INDEX:
5631 // Do nothing, already created
5632 break;
5633 case PRIMARY_KEY_ORDERED_INDEX:
5634 error= create_ordered_index(name, key_info);
5635 break;
5636 case UNIQUE_ORDERED_INDEX:
5637 if (!(error= create_ordered_index(name, key_info)))
5638 error= create_unique_index(unique_name, key_info);
5639 break;
5640 case UNIQUE_INDEX:
5641 if (check_index_fields_not_null(key_info))
5643 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
5644 ER_NULL_COLUMN_IN_INDEX,
5645 "Ndb does not support unique index on NULL valued attributes, index access with NULL value will become full table scan");
5647 error= create_unique_index(unique_name, key_info);
5648 break;
5649 case ORDERED_INDEX:
5650 if (key_info->algorithm == HA_KEY_ALG_HASH)
5652 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
5653 ER_ILLEGAL_HA_CREATE_OPTION,
5654 ER(ER_ILLEGAL_HA_CREATE_OPTION),
5655 ndbcluster_hton_name,
5656 "Ndb does not support non-unique "
5657 "hash based indexes");
5658 error= HA_ERR_UNSUPPORTED;
5659 break;
5661 error= create_ordered_index(name, key_info);
5662 break;
5663 default:
5664 DBUG_ASSERT(FALSE);
5665 break;
5668 DBUG_RETURN(error);
5671 int ha_ndbcluster::create_ordered_index(const char *name,
5672 KEY *key_info)
5674 DBUG_ENTER("ha_ndbcluster::create_ordered_index");
5675 DBUG_RETURN(create_ndb_index(name, key_info, FALSE));
5678 int ha_ndbcluster::create_unique_index(const char *name,
5679 KEY *key_info)
5682 DBUG_ENTER("ha_ndbcluster::create_unique_index");
5683 DBUG_RETURN(create_ndb_index(name, key_info, TRUE));
5688 Create an index in NDB Cluster.
5690 @todo
5691 Only temporary ordered indexes supported
5694 int ha_ndbcluster::create_ndb_index(const char *name,
5695 KEY *key_info,
5696 bool unique)
5698 Ndb *ndb= get_ndb();
5699 NdbDictionary::Dictionary *dict= ndb->getDictionary();
5700 KEY_PART_INFO *key_part= key_info->key_part;
5701 KEY_PART_INFO *end= key_part + key_info->key_parts;
5703 DBUG_ENTER("ha_ndbcluster::create_index");
5704 DBUG_PRINT("enter", ("name: %s ", name));
5706 NdbDictionary::Index ndb_index(name);
5707 if (unique)
5708 ndb_index.setType(NdbDictionary::Index::UniqueHashIndex);
5709 else
5711 ndb_index.setType(NdbDictionary::Index::OrderedIndex);
5712 // TODO Only temporary ordered indexes supported
5713 ndb_index.setLogging(FALSE);
5715 if (ndb_index.setTable(m_tabname))
5717 DBUG_RETURN(my_errno= errno);
5720 for (; key_part != end; key_part++)
5722 Field *field= key_part->field;
5723 DBUG_PRINT("info", ("attr: %s", field->field_name));
5724 if (ndb_index.addColumnName(field->field_name))
5726 DBUG_RETURN(my_errno= errno);
5730 if (dict->createIndex(ndb_index, *m_table))
5731 ERR_RETURN(dict->getNdbError());
5733 // Success
5734 DBUG_PRINT("info", ("Created index %s", name));
5735 DBUG_RETURN(0);
5739 Prepare for an on-line alter table
5741 void ha_ndbcluster::prepare_for_alter()
5743 /* ndb_share reference schema */
5744 ndbcluster_get_share(m_share); // Increase ref_count
5745 DBUG_PRINT("NDB_SHARE", ("%s binlog schema use_count: %u",
5746 m_share->key, m_share->use_count));
5747 set_ndb_share_state(m_share, NSS_ALTERED);
5751 Add an index on-line to a table
5753 int ha_ndbcluster::add_index(TABLE *table_arg,
5754 KEY *key_info, uint num_of_keys)
5756 int error= 0;
5757 uint idx;
5758 DBUG_ENTER("ha_ndbcluster::add_index");
5759 DBUG_PRINT("enter", ("table %s", table_arg->s->table_name.str));
5760 DBUG_ASSERT(m_share->state == NSS_ALTERED);
5762 for (idx= 0; idx < num_of_keys; idx++)
5764 KEY *key= key_info + idx;
5765 KEY_PART_INFO *key_part= key->key_part;
5766 KEY_PART_INFO *end= key_part + key->key_parts;
5767 NDB_INDEX_TYPE idx_type= get_index_type_from_key(idx, key_info, false);
5768 DBUG_PRINT("info", ("Adding index: '%s'", key_info[idx].name));
5769 // Add fields to key_part struct
5770 for (; key_part != end; key_part++)
5771 key_part->field= table->field[key_part->fieldnr];
5772 // Check index type
5773 // Create index in ndb
5774 if((error= create_index(key_info[idx].name, key, idx_type, idx)))
5775 break;
5777 if (error)
5779 set_ndb_share_state(m_share, NSS_INITIAL);
5780 /* ndb_share reference schema free */
5781 DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
5782 m_share->key, m_share->use_count));
5783 free_share(&m_share); // Decrease ref_count
5785 DBUG_RETURN(error);
5789 Mark one or several indexes for deletion. and
5790 renumber the remaining indexes
5792 int ha_ndbcluster::prepare_drop_index(TABLE *table_arg,
5793 uint *key_num, uint num_of_keys)
5795 DBUG_ENTER("ha_ndbcluster::prepare_drop_index");
5796 DBUG_ASSERT(m_share->state == NSS_ALTERED);
5797 // Mark indexes for deletion
5798 uint idx;
5799 for (idx= 0; idx < num_of_keys; idx++)
5801 DBUG_PRINT("info", ("ha_ndbcluster::prepare_drop_index %u", *key_num));
5802 m_index[*key_num++].status= TO_BE_DROPPED;
5804 // Renumber indexes
5805 THD *thd= current_thd;
5806 Thd_ndb *thd_ndb= get_thd_ndb(thd);
5807 Ndb *ndb= thd_ndb->ndb;
5808 renumber_indexes(ndb, table_arg);
5809 DBUG_RETURN(0);
5813 Really drop all indexes marked for deletion
5815 int ha_ndbcluster::final_drop_index(TABLE *table_arg)
5817 int error;
5818 DBUG_ENTER("ha_ndbcluster::final_drop_index");
5819 DBUG_PRINT("info", ("ha_ndbcluster::final_drop_index"));
5820 // Really drop indexes
5821 THD *thd= current_thd;
5822 Thd_ndb *thd_ndb= get_thd_ndb(thd);
5823 Ndb *ndb= thd_ndb->ndb;
5824 if((error= drop_indexes(ndb, table_arg)))
5826 m_share->state= NSS_INITIAL;
5827 /* ndb_share reference schema free */
5828 DBUG_PRINT("NDB_SHARE", ("%s binlog schema free use_count: %u",
5829 m_share->key, m_share->use_count));
5830 free_share(&m_share); // Decrease ref_count
5832 DBUG_RETURN(error);
5836 Rename a table in NDB Cluster.
5839 int ha_ndbcluster::rename_table(const char *from, const char *to)
5841 NDBDICT *dict;
5842 char old_dbname[FN_HEADLEN];
5843 char new_dbname[FN_HEADLEN];
5844 char new_tabname[FN_HEADLEN];
5845 const NDBTAB *orig_tab;
5846 int result;
5847 bool recreate_indexes= FALSE;
5848 NDBDICT::List index_list;
5850 DBUG_ENTER("ha_ndbcluster::rename_table");
5851 DBUG_PRINT("info", ("Renaming %s to %s", from, to));
5852 set_dbname(from, old_dbname);
5853 set_dbname(to, new_dbname);
5854 set_tabname(from);
5855 set_tabname(to, new_tabname);
5857 if (check_ndb_connection())
5858 DBUG_RETURN(my_errno= HA_ERR_NO_CONNECTION);
5860 Ndb *ndb= get_ndb();
5861 ndb->setDatabaseName(old_dbname);
5862 dict= ndb->getDictionary();
5863 Ndb_table_guard ndbtab_g(dict, m_tabname);
5864 if (!(orig_tab= ndbtab_g.get_table()))
5865 ERR_RETURN(dict->getNdbError());
5867 #ifdef HAVE_NDB_BINLOG
5868 int ndb_table_id= orig_tab->getObjectId();
5869 int ndb_table_version= orig_tab->getObjectVersion();
5871 /* ndb_share reference temporary */
5872 NDB_SHARE *share= get_share(from, 0, FALSE);
5873 if (share)
5875 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
5876 share->key, share->use_count));
5877 IF_DBUG(int r=) rename_share(share, to);
5878 DBUG_ASSERT(r == 0);
5880 #endif
5881 if (my_strcasecmp(system_charset_info, new_dbname, old_dbname))
5883 dict->listIndexes(index_list, *orig_tab);
5884 recreate_indexes= TRUE;
5886 // Change current database to that of target table
5887 set_dbname(to);
5888 if (ndb->setDatabaseName(m_dbname))
5890 ERR_RETURN(ndb->getNdbError());
5893 NdbDictionary::Table new_tab= *orig_tab;
5894 new_tab.setName(new_tabname);
5895 if (dict->alterTableGlobal(*orig_tab, new_tab) != 0)
5897 NdbError ndb_error= dict->getNdbError();
5898 #ifdef HAVE_NDB_BINLOG
5899 if (share)
5901 IF_DBUG(int ret=) rename_share(share, from);
5902 DBUG_ASSERT(ret == 0);
5903 /* ndb_share reference temporary free */
5904 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
5905 share->key, share->use_count));
5906 free_share(&share);
5908 #endif
5909 ERR_RETURN(ndb_error);
5912 // Rename .ndb file
5913 if ((result= handler::rename_table(from, to)))
5915 // ToDo in 4.1 should rollback alter table...
5916 #ifdef HAVE_NDB_BINLOG
5917 if (share)
5919 /* ndb_share reference temporary free */
5920 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
5921 share->key, share->use_count));
5922 free_share(&share);
5924 #endif
5925 DBUG_RETURN(result);
5928 #ifdef HAVE_NDB_BINLOG
5929 int is_old_table_tmpfile= 1;
5930 if (share && share->op)
5931 dict->forceGCPWait();
5933 /* handle old table */
5934 if (!IS_TMP_PREFIX(m_tabname))
5936 is_old_table_tmpfile= 0;
5937 String event_name(INJECTOR_EVENT_LEN);
5938 ndb_rep_event_name(&event_name, from + sizeof(share_prefix) - 1, 0);
5939 ndbcluster_handle_drop_table(ndb, event_name.c_ptr(), share,
5940 "rename table");
5943 if (!result && !IS_TMP_PREFIX(new_tabname))
5945 /* always create an event for the table */
5946 String event_name(INJECTOR_EVENT_LEN);
5947 ndb_rep_event_name(&event_name, to + sizeof(share_prefix) - 1, 0);
5948 Ndb_table_guard ndbtab_g2(dict, new_tabname);
5949 const NDBTAB *ndbtab= ndbtab_g2.get_table();
5951 if (!ndbcluster_create_event(ndb, ndbtab, event_name.c_ptr(), share,
5952 share && ndb_binlog_running ? 2 : 1/* push warning */))
5954 if (ndb_extra_logging)
5955 sql_print_information("NDB Binlog: RENAME Event: %s",
5956 event_name.c_ptr());
5957 if (share &&
5958 ndbcluster_create_event_ops(share, ndbtab, event_name.c_ptr()))
5960 sql_print_error("NDB Binlog: FAILED create event operations "
5961 "during RENAME. Event %s", event_name.c_ptr());
5962 /* a warning has been issued to the client */
5966 warning has been issued if ndbcluster_create_event failed
5967 and (share && ndb_binlog_running)
5969 if (!is_old_table_tmpfile)
5970 ndbcluster_log_schema_op(current_thd, share,
5971 current_thd->query(),
5972 current_thd->query_length(),
5973 old_dbname, m_tabname,
5974 ndb_table_id, ndb_table_version,
5975 SOT_RENAME_TABLE,
5976 m_dbname, new_tabname, 1);
5979 // If we are moving tables between databases, we need to recreate
5980 // indexes
5981 if (recreate_indexes)
5983 for (unsigned i = 0; i < index_list.count; i++)
5985 NDBDICT::List::Element& index_el = index_list.elements[i];
5986 // Recreate any indexes not stored in the system database
5987 if (my_strcasecmp(system_charset_info,
5988 index_el.database, NDB_SYSTEM_DATABASE))
5990 set_dbname(from);
5991 ndb->setDatabaseName(m_dbname);
5992 const NDBINDEX * index= dict->getIndexGlobal(index_el.name, new_tab);
5993 DBUG_PRINT("info", ("Creating index %s/%s",
5994 index_el.database, index->getName()));
5995 dict->createIndex(*index, new_tab);
5996 DBUG_PRINT("info", ("Dropping index %s/%s",
5997 index_el.database, index->getName()));
5998 set_dbname(from);
5999 ndb->setDatabaseName(m_dbname);
6000 dict->dropIndexGlobal(*index);
6004 if (share)
6006 /* ndb_share reference temporary free */
6007 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6008 share->key, share->use_count));
6009 free_share(&share);
6011 #endif
6013 DBUG_RETURN(result);
6018 Delete table from NDB Cluster.
6021 /* static version which does not need a handler */
6024 ha_ndbcluster::delete_table(ha_ndbcluster *h, Ndb *ndb,
6025 const char *path,
6026 const char *db,
6027 const char *table_name)
6029 THD *thd= current_thd;
6030 DBUG_ENTER("ha_ndbcluster::ndbcluster_delete_table");
6031 NDBDICT *dict= ndb->getDictionary();
6032 int ndb_table_id= 0;
6033 int ndb_table_version= 0;
6034 #ifdef HAVE_NDB_BINLOG
6036 Don't allow drop table unless
6037 schema distribution table is setup
6039 if (!ndb_schema_share)
6041 DBUG_PRINT("info", ("Schema distribution table not setup"));
6042 DBUG_ASSERT(ndb_schema_share);
6043 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6045 /* ndb_share reference temporary */
6046 NDB_SHARE *share= get_share(path, 0, FALSE);
6047 if (share)
6049 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
6050 share->key, share->use_count));
6052 #endif
6054 /* Drop the table from NDB */
6056 int res= 0;
6057 if (h && h->m_table)
6059 retry_temporary_error1:
6060 if (dict->dropTableGlobal(*h->m_table) == 0)
6062 ndb_table_id= h->m_table->getObjectId();
6063 ndb_table_version= h->m_table->getObjectVersion();
6064 DBUG_PRINT("info", ("success 1"));
6066 else
6068 switch (dict->getNdbError().status)
6070 case NdbError::TemporaryError:
6071 if (!thd->killed)
6072 goto retry_temporary_error1; // retry indefinitly
6073 break;
6074 default:
6075 break;
6077 set_ndb_err(thd, dict->getNdbError());
6078 res= ndb_to_mysql_error(&dict->getNdbError());
6079 DBUG_PRINT("info", ("error(1) %u", res));
6081 h->release_metadata(thd, ndb);
6083 else
6085 ndb->setDatabaseName(db);
6086 while (1)
6088 Ndb_table_guard ndbtab_g(dict, table_name);
6089 if (ndbtab_g.get_table())
6091 retry_temporary_error2:
6092 if (dict->dropTableGlobal(*ndbtab_g.get_table()) == 0)
6094 ndb_table_id= ndbtab_g.get_table()->getObjectId();
6095 ndb_table_version= ndbtab_g.get_table()->getObjectVersion();
6096 DBUG_PRINT("info", ("success 2"));
6097 break;
6099 else
6101 switch (dict->getNdbError().status)
6103 case NdbError::TemporaryError:
6104 if (!thd->killed)
6105 goto retry_temporary_error2; // retry indefinitly
6106 break;
6107 default:
6108 if (dict->getNdbError().code == NDB_INVALID_SCHEMA_OBJECT)
6110 ndbtab_g.invalidate();
6111 continue;
6113 break;
6117 set_ndb_err(thd, dict->getNdbError());
6118 res= ndb_to_mysql_error(&dict->getNdbError());
6119 DBUG_PRINT("info", ("error(2) %u", res));
6120 break;
6124 if (res)
6126 #ifdef HAVE_NDB_BINLOG
6127 /* the drop table failed for some reason, drop the share anyways */
6128 if (share)
6130 pthread_mutex_lock(&ndbcluster_mutex);
6131 if (share->state != NSS_DROPPED)
6134 The share kept by the server has not been freed, free it
6136 share->state= NSS_DROPPED;
6137 /* ndb_share reference create free */
6138 DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
6139 share->key, share->use_count));
6140 free_share(&share, TRUE);
6142 /* ndb_share reference temporary free */
6143 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6144 share->key, share->use_count));
6145 free_share(&share, TRUE);
6146 pthread_mutex_unlock(&ndbcluster_mutex);
6148 #endif
6149 DBUG_RETURN(res);
6152 #ifdef HAVE_NDB_BINLOG
6153 /* stop the logging of the dropped table, and cleanup */
6156 drop table is successful even if table does not exist in ndb
6157 and in case table was actually not dropped, there is no need
6158 to force a gcp, and setting the event_name to null will indicate
6159 that there is no event to be dropped
6161 int table_dropped= dict->getNdbError().code != 709;
6163 if (!IS_TMP_PREFIX(table_name) && share &&
6164 current_thd->lex->sql_command != SQLCOM_TRUNCATE)
6166 ndbcluster_log_schema_op(thd, share,
6167 thd->query(), thd->query_length(),
6168 share->db, share->table_name,
6169 ndb_table_id, ndb_table_version,
6170 SOT_DROP_TABLE, 0, 0, 1);
6172 else if (table_dropped && share && share->op) /* ndbcluster_log_schema_op
6173 will do a force GCP */
6174 dict->forceGCPWait();
6176 if (!IS_TMP_PREFIX(table_name))
6178 String event_name(INJECTOR_EVENT_LEN);
6179 ndb_rep_event_name(&event_name, path + sizeof(share_prefix) - 1, 0);
6180 ndbcluster_handle_drop_table(ndb,
6181 table_dropped ? event_name.c_ptr() : 0,
6182 share, "delete table");
6185 if (share)
6187 pthread_mutex_lock(&ndbcluster_mutex);
6188 if (share->state != NSS_DROPPED)
6191 The share kept by the server has not been freed, free it
6193 share->state= NSS_DROPPED;
6194 /* ndb_share reference create free */
6195 DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
6196 share->key, share->use_count));
6197 free_share(&share, TRUE);
6199 /* ndb_share reference temporary free */
6200 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6201 share->key, share->use_count));
6202 free_share(&share, TRUE);
6203 pthread_mutex_unlock(&ndbcluster_mutex);
6205 #endif
6206 DBUG_RETURN(0);
6209 int ha_ndbcluster::delete_table(const char *name)
6211 DBUG_ENTER("ha_ndbcluster::delete_table");
6212 DBUG_PRINT("enter", ("name: %s", name));
6213 set_dbname(name);
6214 set_tabname(name);
6216 #ifdef HAVE_NDB_BINLOG
6218 Don't allow drop table unless
6219 schema distribution table is setup
6221 if (!ndb_schema_share)
6223 DBUG_PRINT("info", ("Schema distribution table not setup"));
6224 DBUG_ASSERT(ndb_schema_share);
6225 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6227 #endif
6229 if (check_ndb_connection())
6230 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6232 /* Call ancestor function to delete .ndb file */
6233 handler::delete_table(name);
6235 DBUG_RETURN(delete_table(this, get_ndb(),name, m_dbname, m_tabname));
6239 void ha_ndbcluster::get_auto_increment(ulonglong offset, ulonglong increment,
6240 ulonglong nb_desired_values,
6241 ulonglong *first_value,
6242 ulonglong *nb_reserved_values)
6244 uint cache_size;
6245 Uint64 auto_value;
6246 THD *thd= current_thd;
6247 DBUG_ENTER("get_auto_increment");
6248 DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
6249 Ndb *ndb= get_ndb();
6251 if (m_rows_inserted > m_rows_to_insert)
6253 /* We guessed too low */
6254 m_rows_to_insert+= m_autoincrement_prefetch;
6256 uint remaining= m_rows_to_insert - m_rows_inserted;
6257 uint min_prefetch=
6258 (remaining < thd->variables.ndb_autoincrement_prefetch_sz) ?
6259 thd->variables.ndb_autoincrement_prefetch_sz
6260 : remaining;
6261 cache_size= ((remaining < m_autoincrement_prefetch) ?
6262 min_prefetch
6263 : remaining);
6264 uint retries= NDB_AUTO_INCREMENT_RETRIES;
6265 int retry_sleep= 30; /* 30 milliseconds, transaction */
6266 for (;;)
6268 Ndb_tuple_id_range_guard g(m_share);
6269 if ((m_skip_auto_increment &&
6270 ndb->readAutoIncrementValue(m_table, g.range, auto_value)) ||
6271 ndb->getAutoIncrementValue(m_table, g.range, auto_value, cache_size, increment, offset))
6273 if (--retries &&
6274 ndb->getNdbError().status == NdbError::TemporaryError)
6276 my_sleep(retry_sleep);
6277 continue;
6279 const NdbError err= ndb->getNdbError();
6280 sql_print_error("Error %lu in ::get_auto_increment(): %s",
6281 (ulong) err.code, err.message);
6282 *first_value= ~(ulonglong) 0;
6283 DBUG_VOID_RETURN;
6285 break;
6287 *first_value= (longlong)auto_value;
6288 /* From the point of view of MySQL, NDB reserves one row at a time */
6289 *nb_reserved_values= 1;
6290 DBUG_VOID_RETURN;
6295 Constructor for the NDB Cluster table handler .
6299 Normal flags for binlogging is that ndb has HA_HAS_OWN_BINLOGGING
6300 and preferes HA_BINLOG_ROW_CAPABLE
6301 Other flags are set under certain circumstaces in table_flags()
6303 #define HA_NDBCLUSTER_TABLE_FLAGS \
6304 HA_REC_NOT_IN_SEQ | \
6305 HA_NULL_IN_KEY | \
6306 HA_AUTO_PART_KEY | \
6307 HA_NO_PREFIX_CHAR_KEYS | \
6308 HA_NEED_READ_RANGE_BUFFER | \
6309 HA_CAN_GEOMETRY | \
6310 HA_CAN_BIT_FIELD | \
6311 HA_PRIMARY_KEY_REQUIRED_FOR_POSITION | \
6312 HA_PRIMARY_KEY_REQUIRED_FOR_DELETE | \
6313 HA_PARTIAL_COLUMN_READ | \
6314 HA_HAS_OWN_BINLOGGING | \
6315 HA_BINLOG_ROW_CAPABLE | \
6316 HA_HAS_RECORDS
6318 ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
6319 handler(hton, table_arg),
6320 m_active_trans(NULL),
6321 m_active_cursor(NULL),
6322 m_table(NULL),
6323 m_table_info(NULL),
6324 m_table_flags(HA_NDBCLUSTER_TABLE_FLAGS),
6325 m_share(0),
6326 m_part_info(NULL),
6327 m_use_partition_function(FALSE),
6328 m_sorted(FALSE),
6329 m_use_write(FALSE),
6330 m_ignore_dup_key(FALSE),
6331 m_has_unique_index(FALSE),
6332 m_primary_key_update(FALSE),
6333 m_ignore_no_key(FALSE),
6334 m_rows_to_insert((ha_rows) 1),
6335 m_rows_inserted((ha_rows) 0),
6336 m_bulk_insert_rows((ha_rows) 1024),
6337 m_rows_changed((ha_rows) 0),
6338 m_bulk_insert_not_flushed(FALSE),
6339 m_delete_cannot_batch(FALSE),
6340 m_update_cannot_batch(FALSE),
6341 m_ops_pending(0),
6342 m_skip_auto_increment(TRUE),
6343 m_blobs_pending(0),
6344 m_blobs_offset(0),
6345 m_blobs_buffer(0),
6346 m_blobs_buffer_size(0),
6347 m_dupkey((uint) -1),
6348 m_ha_not_exact_count(FALSE),
6349 m_force_send(TRUE),
6350 m_autoincrement_prefetch((ha_rows) NDB_DEFAULT_AUTO_PREFETCH),
6351 m_transaction_on(TRUE),
6352 m_cond(NULL),
6353 m_multi_cursor(NULL)
6355 int i;
6357 DBUG_ENTER("ha_ndbcluster");
6359 m_tabname[0]= '\0';
6360 m_dbname[0]= '\0';
6362 stats.records= ~(ha_rows)0; // uninitialized
6363 stats.block_size= 1024;
6365 for (i= 0; i < MAX_KEY; i++)
6366 ndb_init_index(m_index[i]);
6368 DBUG_VOID_RETURN;
6372 int ha_ndbcluster::ha_initialise()
6374 DBUG_ENTER("ha_ndbcluster::ha_initialise");
6375 if (check_ndb_in_thd(current_thd))
6377 DBUG_RETURN(FALSE);
6379 DBUG_RETURN(TRUE);
6383 Destructor for NDB Cluster table handler.
6386 ha_ndbcluster::~ha_ndbcluster()
6388 THD *thd= current_thd;
6389 Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
6390 DBUG_ENTER("~ha_ndbcluster");
6392 if (m_share)
6394 /* ndb_share reference handler free */
6395 DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
6396 m_share->key, m_share->use_count));
6397 free_share(&m_share);
6399 release_metadata(thd, ndb);
6400 my_free(m_blobs_buffer, MYF(MY_ALLOW_ZERO_PTR));
6401 m_blobs_buffer= 0;
6403 // Check for open cursor/transaction
6404 if (m_active_cursor) {
6406 DBUG_ASSERT(m_active_cursor == NULL);
6407 if (m_active_trans) {
6409 DBUG_ASSERT(m_active_trans == NULL);
6411 // Discard any generated condition
6412 DBUG_PRINT("info", ("Deleting generated condition"));
6413 if (m_cond)
6415 delete m_cond;
6416 m_cond= NULL;
6419 DBUG_VOID_RETURN;
6425 Open a table for further use.
6427 - fetch metadata for this table from NDB
6428 - check that table exists
6430 @retval
6431 0 ok
6432 @retval
6433 < 0 Table has changed
6436 int ha_ndbcluster::open(const char *name, int mode, uint test_if_locked)
6438 int res;
6439 KEY *key;
6440 DBUG_ENTER("ha_ndbcluster::open");
6441 DBUG_PRINT("enter", ("name: %s mode: %d test_if_locked: %d",
6442 name, mode, test_if_locked));
6445 Setup ref_length to make room for the whole
6446 primary key to be written in the ref variable
6449 if (table_share->primary_key != MAX_KEY)
6451 key= table->key_info+table_share->primary_key;
6452 ref_length= key->key_length;
6454 else // (table_share->primary_key == MAX_KEY)
6456 if (m_use_partition_function)
6458 ref_length+= sizeof(m_part_id);
6462 DBUG_PRINT("info", ("ref_length: %d", ref_length));
6464 // Init table lock structure
6465 /* ndb_share reference handler */
6466 if (!(m_share=get_share(name, table)))
6467 DBUG_RETURN(1);
6468 DBUG_PRINT("NDB_SHARE", ("%s handler use_count: %u",
6469 m_share->key, m_share->use_count));
6470 thr_lock_data_init(&m_share->lock,&m_lock,(void*) 0);
6472 set_dbname(name);
6473 set_tabname(name);
6475 if ((res= check_ndb_connection()) ||
6476 (res= get_metadata(name)))
6478 /* ndb_share reference handler free */
6479 DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
6480 m_share->key, m_share->use_count));
6481 free_share(&m_share);
6482 m_share= 0;
6483 DBUG_RETURN(res);
6485 while (1)
6487 Ndb *ndb= get_ndb();
6488 if (ndb->setDatabaseName(m_dbname))
6490 set_ndb_err(current_thd, ndb->getNdbError());
6491 res= ndb_to_mysql_error(&ndb->getNdbError());
6492 break;
6494 struct Ndb_statistics stat;
6495 res= ndb_get_table_statistics(NULL, FALSE, ndb, m_table, &stat);
6496 stats.mean_rec_length= stat.row_size;
6497 stats.data_file_length= stat.fragment_memory;
6498 stats.records= stat.row_count;
6499 if(!res)
6500 res= info(HA_STATUS_CONST);
6501 break;
6503 if (res)
6505 free_share(&m_share);
6506 m_share= 0;
6507 release_metadata(current_thd, get_ndb());
6508 DBUG_RETURN(res);
6510 #ifdef HAVE_NDB_BINLOG
6511 if (!ndb_binlog_tables_inited)
6513 table->db_stat|= HA_READ_ONLY;
6514 sql_print_information("table '%s' opened read only", name);
6516 #endif
6517 DBUG_RETURN(0);
6521 Set partition info
6523 SYNOPSIS
6524 set_part_info()
6525 part_info
6527 RETURN VALUE
6528 NONE
6530 DESCRIPTION
6531 Set up partition info when handler object created
6534 void ha_ndbcluster::set_part_info(partition_info *part_info)
6536 m_part_info= part_info;
6537 if (!(m_part_info->part_type == HASH_PARTITION &&
6538 m_part_info->list_of_part_fields &&
6539 !m_part_info->is_sub_partitioned()))
6540 m_use_partition_function= TRUE;
6544 Close the table; release resources setup by open().
6547 int ha_ndbcluster::close(void)
6549 DBUG_ENTER("close");
6550 THD *thd= table->in_use;
6551 Ndb *ndb= thd ? check_ndb_in_thd(thd) : g_ndb;
6552 /* ndb_share reference handler free */
6553 DBUG_PRINT("NDB_SHARE", ("%s handler free use_count: %u",
6554 m_share->key, m_share->use_count));
6555 free_share(&m_share);
6556 m_share= 0;
6557 release_metadata(thd, ndb);
6558 DBUG_RETURN(0);
6563 @todo
6564 - Alt.1 If init fails because to many allocated Ndb
6565 wait on condition for a Ndb object to be released.
6566 - Alt.2 Seize/release from pool, wait until next release
6568 Thd_ndb* ha_ndbcluster::seize_thd_ndb()
6570 Thd_ndb *thd_ndb;
6571 DBUG_ENTER("seize_thd_ndb");
6573 thd_ndb= new Thd_ndb();
6574 if (thd_ndb == NULL)
6576 my_errno= HA_ERR_OUT_OF_MEM;
6577 return NULL;
6579 if (thd_ndb->ndb->init(max_transactions) != 0)
6581 ERR_PRINT(thd_ndb->ndb->getNdbError());
6583 TODO
6584 Alt.1 If init fails because to many allocated Ndb
6585 wait on condition for a Ndb object to be released.
6586 Alt.2 Seize/release from pool, wait until next release
6588 delete thd_ndb;
6589 thd_ndb= NULL;
6591 DBUG_RETURN(thd_ndb);
6595 void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb)
6597 DBUG_ENTER("release_thd_ndb");
6598 delete thd_ndb;
6599 DBUG_VOID_RETURN;
6604 If this thread already has a Thd_ndb object allocated
6605 in current THD, reuse it. Otherwise
6606 seize a Thd_ndb object, assign it to current THD and use it.
6610 Ndb* check_ndb_in_thd(THD* thd)
6612 Thd_ndb *thd_ndb= get_thd_ndb(thd);
6613 if (!thd_ndb)
6615 if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
6616 return NULL;
6617 set_thd_ndb(thd, thd_ndb);
6619 return thd_ndb->ndb;
6624 int ha_ndbcluster::check_ndb_connection(THD* thd)
6626 Ndb *ndb;
6627 DBUG_ENTER("check_ndb_connection");
6629 if (!(ndb= check_ndb_in_thd(thd)))
6630 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6631 if (ndb->setDatabaseName(m_dbname))
6633 ERR_RETURN(ndb->getNdbError());
6635 DBUG_RETURN(0);
6639 static int ndbcluster_close_connection(handlerton *hton, THD *thd)
6641 Thd_ndb *thd_ndb= get_thd_ndb(thd);
6642 DBUG_ENTER("ndbcluster_close_connection");
6643 if (thd_ndb)
6645 ha_ndbcluster::release_thd_ndb(thd_ndb);
6646 set_thd_ndb(thd, NULL); // not strictly required but does not hurt either
6648 DBUG_RETURN(0);
6653 Try to discover one table from NDB.
6656 int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
6657 const char *name,
6658 uchar **frmblob,
6659 size_t *frmlen)
6661 int error= 0;
6662 NdbError ndb_error;
6663 size_t len;
6664 uchar* data= NULL;
6665 Ndb* ndb;
6666 char key[FN_REFLEN + 1];
6667 DBUG_ENTER("ndbcluster_discover");
6668 DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
6670 if (!(ndb= check_ndb_in_thd(thd)))
6671 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6672 if (ndb->setDatabaseName(db))
6674 ERR_RETURN(ndb->getNdbError());
6676 NDBDICT* dict= ndb->getDictionary();
6677 build_table_filename(key, sizeof(key) - 1, db, name, "", 0);
6678 /* ndb_share reference temporary */
6679 NDB_SHARE *share= get_share(key, 0, FALSE);
6680 if (share)
6682 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
6683 share->key, share->use_count));
6685 if (share && get_ndb_share_state(share) == NSS_ALTERED)
6687 // Frm has been altered on disk, but not yet written to ndb
6688 if (readfrm(key, &data, &len))
6690 DBUG_PRINT("error", ("Could not read frm"));
6691 error= 1;
6692 goto err;
6695 else
6697 Ndb_table_guard ndbtab_g(dict, name);
6698 const NDBTAB *tab= ndbtab_g.get_table();
6699 if (!tab)
6701 const NdbError err= dict->getNdbError();
6702 if (err.code == 709 || err.code == 723)
6704 error= -1;
6705 DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error.code));
6707 else
6709 error= -1;
6710 ndb_error= err;
6711 DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error.code));
6713 goto err;
6715 DBUG_PRINT("info", ("Found table %s", tab->getName()));
6717 len= tab->getFrmLength();
6718 if (len == 0 || tab->getFrmData() == NULL)
6720 DBUG_PRINT("error", ("No frm data found."));
6721 error= 1;
6722 goto err;
6725 if (unpackfrm(&data, &len, (uchar*) tab->getFrmData()))
6727 DBUG_PRINT("error", ("Could not unpack table"));
6728 error= 1;
6729 goto err;
6733 *frmlen= len;
6734 *frmblob= data;
6736 if (share)
6738 /* ndb_share reference temporary free */
6739 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6740 share->key, share->use_count));
6741 free_share(&share);
6744 DBUG_RETURN(0);
6745 err:
6746 my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR));
6747 if (share)
6749 /* ndb_share reference temporary free */
6750 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6751 share->key, share->use_count));
6752 free_share(&share);
6754 if (ndb_error.code)
6756 ERR_RETURN(ndb_error);
6758 DBUG_RETURN(error);
6762 Check if a table exists in NDB.
6765 int ndbcluster_table_exists_in_engine(handlerton *hton, THD* thd,
6766 const char *db,
6767 const char *name)
6769 Ndb* ndb;
6770 DBUG_ENTER("ndbcluster_table_exists_in_engine");
6771 DBUG_PRINT("enter", ("db: %s name: %s", db, name));
6773 if (!(ndb= check_ndb_in_thd(thd)))
6774 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6775 NDBDICT* dict= ndb->getDictionary();
6776 NdbDictionary::Dictionary::List list;
6777 if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
6778 ERR_RETURN(dict->getNdbError());
6779 for (uint i= 0 ; i < list.count ; i++)
6781 NdbDictionary::Dictionary::List::Element& elmt= list.elements[i];
6782 if (my_strcasecmp(system_charset_info, elmt.database, db))
6783 continue;
6784 if (my_strcasecmp(system_charset_info, elmt.name, name))
6785 continue;
6786 DBUG_PRINT("info", ("Found table"));
6787 DBUG_RETURN(HA_ERR_TABLE_EXIST);
6789 DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
6794 extern "C" uchar* tables_get_key(const char *entry, size_t *length,
6795 my_bool not_used __attribute__((unused)))
6797 *length= strlen(entry);
6798 return (uchar*) entry;
6803 Drop a database in NDB Cluster
6805 @note
6806 add a dummy void function, since stupid handlerton is returning void instead of int...
6808 int ndbcluster_drop_database_impl(const char *path)
6810 DBUG_ENTER("ndbcluster_drop_database");
6811 THD *thd= current_thd;
6812 char dbname[FN_HEADLEN];
6813 Ndb* ndb;
6814 NdbDictionary::Dictionary::List list;
6815 uint i;
6816 char *tabname;
6817 List<char> drop_list;
6818 int ret= 0;
6819 ha_ndbcluster::set_dbname(path, (char *)&dbname);
6820 DBUG_PRINT("enter", ("db: %s", dbname));
6822 if (!(ndb= check_ndb_in_thd(thd)))
6823 DBUG_RETURN(-1);
6825 // List tables in NDB
6826 NDBDICT *dict= ndb->getDictionary();
6827 if (dict->listObjects(list,
6828 NdbDictionary::Object::UserTable) != 0)
6829 DBUG_RETURN(-1);
6830 for (i= 0 ; i < list.count ; i++)
6832 NdbDictionary::Dictionary::List::Element& elmt= list.elements[i];
6833 DBUG_PRINT("info", ("Found %s/%s in NDB", elmt.database, elmt.name));
6835 // Add only tables that belongs to db
6836 if (my_strcasecmp(system_charset_info, elmt.database, dbname))
6837 continue;
6838 DBUG_PRINT("info", ("%s must be dropped", elmt.name));
6839 drop_list.push_back(thd->strdup(elmt.name));
6841 // Drop any tables belonging to database
6842 char full_path[FN_REFLEN + 1];
6843 char *tmp= full_path +
6844 build_table_filename(full_path, sizeof(full_path) - 1, dbname, "", "", 0);
6845 if (ndb->setDatabaseName(dbname))
6847 ERR_RETURN(ndb->getNdbError());
6849 List_iterator_fast<char> it(drop_list);
6850 while ((tabname=it++))
6852 tablename_to_filename(tabname, tmp, FN_REFLEN - (tmp - full_path)-1);
6853 VOID(pthread_mutex_lock(&LOCK_open));
6854 if (ha_ndbcluster::delete_table(0, ndb, full_path, dbname, tabname))
6856 const NdbError err= dict->getNdbError();
6857 if (err.code != 709 && err.code != 723)
6859 set_ndb_err(thd, err);
6860 ret= ndb_to_mysql_error(&err);
6863 VOID(pthread_mutex_unlock(&LOCK_open));
6865 DBUG_RETURN(ret);
6868 static void ndbcluster_drop_database(handlerton *hton, char *path)
6870 DBUG_ENTER("ndbcluster_drop_database");
6871 #ifdef HAVE_NDB_BINLOG
6873 Don't allow drop database unless
6874 schema distribution table is setup
6876 if (!ndb_schema_share)
6878 DBUG_PRINT("info", ("Schema distribution table not setup"));
6879 DBUG_ASSERT(ndb_schema_share);
6880 DBUG_VOID_RETURN;
6882 #endif
6883 ndbcluster_drop_database_impl(path);
6884 #ifdef HAVE_NDB_BINLOG
6885 char db[FN_REFLEN];
6886 THD *thd= current_thd;
6887 ha_ndbcluster::set_dbname(path, db);
6888 ndbcluster_log_schema_op(thd, 0,
6889 thd->query(), thd->query_length(),
6890 db, "", 0, 0, SOT_DROP_DB, 0, 0, 0);
6891 #endif
6892 DBUG_VOID_RETURN;
6895 int ndb_create_table_from_engine(THD *thd, const char *db,
6896 const char *table_name)
6898 LEX *old_lex= thd->lex, newlex;
6899 thd->lex= &newlex;
6900 newlex.current_select= NULL;
6901 lex_start(thd);
6902 int res= ha_create_table_from_engine(thd, db, table_name);
6903 thd->lex= old_lex;
6904 return res;
6908 find all tables in ndb and discover those needed
6910 int ndbcluster_find_all_files(THD *thd)
6912 Ndb* ndb;
6913 char key[FN_REFLEN + 1];
6914 NDBDICT *dict;
6915 int unhandled, retries= 5, skipped;
6916 DBUG_ENTER("ndbcluster_find_all_files");
6918 if (!(ndb= check_ndb_in_thd(thd)))
6919 DBUG_RETURN(HA_ERR_NO_CONNECTION);
6921 dict= ndb->getDictionary();
6923 LINT_INIT(unhandled);
6924 LINT_INIT(skipped);
6927 NdbDictionary::Dictionary::List list;
6928 if (dict->listObjects(list, NdbDictionary::Object::UserTable) != 0)
6929 ERR_RETURN(dict->getNdbError());
6930 unhandled= 0;
6931 skipped= 0;
6932 retries--;
6933 for (uint i= 0 ; i < list.count ; i++)
6935 NDBDICT::List::Element& elmt= list.elements[i];
6936 if (IS_TMP_PREFIX(elmt.name) || IS_NDB_BLOB_PREFIX(elmt.name))
6938 DBUG_PRINT("info", ("Skipping %s.%s in NDB", elmt.database, elmt.name));
6939 continue;
6941 DBUG_PRINT("info", ("Found %s.%s in NDB", elmt.database, elmt.name));
6942 if (elmt.state != NDBOBJ::StateOnline &&
6943 elmt.state != NDBOBJ::StateBackup &&
6944 elmt.state != NDBOBJ::StateBuilding)
6946 sql_print_information("NDB: skipping setup table %s.%s, in state %d",
6947 elmt.database, elmt.name, elmt.state);
6948 skipped++;
6949 continue;
6952 ndb->setDatabaseName(elmt.database);
6953 Ndb_table_guard ndbtab_g(dict, elmt.name);
6954 const NDBTAB *ndbtab= ndbtab_g.get_table();
6955 if (!ndbtab)
6957 if (retries == 0)
6958 sql_print_error("NDB: failed to setup table %s.%s, error: %d, %s",
6959 elmt.database, elmt.name,
6960 dict->getNdbError().code,
6961 dict->getNdbError().message);
6962 unhandled++;
6963 continue;
6966 if (ndbtab->getFrmLength() == 0)
6967 continue;
6969 /* check if database exists */
6970 char *end= key +
6971 build_table_filename(key, sizeof(key) - 1, elmt.database, "", "", 0);
6972 if (my_access(key, F_OK))
6974 /* no such database defined, skip table */
6975 continue;
6977 /* finalize construction of path */
6978 end+= tablename_to_filename(elmt.name, end,
6979 sizeof(key)-(end-key));
6980 uchar *data= 0, *pack_data= 0;
6981 size_t length, pack_length;
6982 int discover= 0;
6983 if (readfrm(key, &data, &length) ||
6984 packfrm(data, length, &pack_data, &pack_length))
6986 discover= 1;
6987 sql_print_information("NDB: missing frm for %s.%s, discovering...",
6988 elmt.database, elmt.name);
6990 else if (cmp_frm(ndbtab, pack_data, pack_length))
6992 /* ndb_share reference temporary */
6993 NDB_SHARE *share= get_share(key, 0, FALSE);
6994 if (share)
6996 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
6997 share->key, share->use_count));
6999 if (!share || get_ndb_share_state(share) != NSS_ALTERED)
7001 discover= 1;
7002 sql_print_information("NDB: mismatch in frm for %s.%s, discovering...",
7003 elmt.database, elmt.name);
7005 if (share)
7007 /* ndb_share reference temporary free */
7008 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
7009 share->key, share->use_count));
7010 free_share(&share);
7013 my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR));
7014 my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR));
7016 pthread_mutex_lock(&LOCK_open);
7017 if (discover)
7019 /* ToDo 4.1 database needs to be created if missing */
7020 if (ndb_create_table_from_engine(thd, elmt.database, elmt.name))
7022 /* ToDo 4.1 handle error */
7025 #ifdef HAVE_NDB_BINLOG
7026 else
7028 /* set up replication for this table */
7029 ndbcluster_create_binlog_setup(ndb, key, end-key,
7030 elmt.database, elmt.name,
7031 TRUE);
7033 #endif
7034 pthread_mutex_unlock(&LOCK_open);
7037 while (unhandled && retries);
7039 DBUG_RETURN(-(skipped + unhandled));
7042 int ndbcluster_find_files(handlerton *hton, THD *thd,
7043 const char *db,
7044 const char *path,
7045 const char *wild, bool dir, List<LEX_STRING> *files)
7047 DBUG_ENTER("ndbcluster_find_files");
7048 DBUG_PRINT("enter", ("db: %s", db));
7049 { // extra bracket to avoid gcc 2.95.3 warning
7050 uint i;
7051 Ndb* ndb;
7052 char name[FN_REFLEN + 1];
7053 HASH ndb_tables, ok_tables;
7054 NDBDICT::List list;
7056 if (!(ndb= check_ndb_in_thd(thd)))
7057 DBUG_RETURN(HA_ERR_NO_CONNECTION);
7059 if (dir)
7060 DBUG_RETURN(0); // Discover of databases not yet supported
7062 // List tables in NDB
7063 NDBDICT *dict= ndb->getDictionary();
7064 if (dict->listObjects(list,
7065 NdbDictionary::Object::UserTable) != 0)
7066 ERR_RETURN(dict->getNdbError());
7068 if (hash_init(&ndb_tables, system_charset_info,list.count,0,0,
7069 (hash_get_key)tables_get_key,0,0))
7071 DBUG_PRINT("error", ("Failed to init HASH ndb_tables"));
7072 DBUG_RETURN(-1);
7075 if (hash_init(&ok_tables, system_charset_info,32,0,0,
7076 (hash_get_key)tables_get_key,0,0))
7078 DBUG_PRINT("error", ("Failed to init HASH ok_tables"));
7079 hash_free(&ndb_tables);
7080 DBUG_RETURN(-1);
7083 for (i= 0 ; i < list.count ; i++)
7085 NDBDICT::List::Element& elmt= list.elements[i];
7086 if (IS_TMP_PREFIX(elmt.name) || IS_NDB_BLOB_PREFIX(elmt.name))
7088 DBUG_PRINT("info", ("Skipping %s.%s in NDB", elmt.database, elmt.name));
7089 continue;
7091 DBUG_PRINT("info", ("Found %s/%s in NDB", elmt.database, elmt.name));
7093 // Add only tables that belongs to db
7094 if (my_strcasecmp(system_charset_info, elmt.database, db))
7095 continue;
7097 // Apply wildcard to list of tables in NDB
7098 if (wild)
7100 if (lower_case_table_names)
7102 if (wild_case_compare(files_charset_info, elmt.name, wild))
7103 continue;
7105 else if (wild_compare(elmt.name,wild,0))
7106 continue;
7108 DBUG_PRINT("info", ("Inserting %s into ndb_tables hash", elmt.name));
7109 my_hash_insert(&ndb_tables, (uchar*)thd->strdup(elmt.name));
7112 LEX_STRING *file_name;
7113 List_iterator<LEX_STRING> it(*files);
7114 List<char> delete_list;
7115 char *file_name_str;
7116 while ((file_name=it++))
7118 bool file_on_disk= FALSE;
7119 DBUG_PRINT("info", ("%s", file_name->str));
7120 if (hash_search(&ndb_tables, (uchar*) file_name->str, file_name->length))
7122 build_table_filename(name, sizeof(name) - 1, db,
7123 file_name->str, reg_ext, 0);
7124 if (my_access(name, F_OK))
7126 pthread_mutex_lock(&LOCK_open);
7127 DBUG_PRINT("info", ("Table %s listed and need discovery",
7128 file_name->str));
7129 if (ndb_create_table_from_engine(thd, db, file_name->str))
7131 pthread_mutex_unlock(&LOCK_open);
7132 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
7133 ER_TABLE_EXISTS_ERROR,
7134 "Discover of table %s.%s failed",
7135 db, file_name->str);
7136 continue;
7138 pthread_mutex_unlock(&LOCK_open);
7140 DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name->str));
7141 file_on_disk= TRUE;
7144 // Check for .ndb file with this name
7145 build_table_filename(name, sizeof(name) - 1, db,
7146 file_name->str, ha_ndb_ext, 0);
7147 DBUG_PRINT("info", ("Check access for %s", name));
7148 if (my_access(name, F_OK))
7150 DBUG_PRINT("info", ("%s did not exist on disk", name));
7151 // .ndb file did not exist on disk, another table type
7152 if (file_on_disk)
7154 // Ignore this ndb table
7155 uchar *record= hash_search(&ndb_tables, (uchar*) file_name->str,
7156 file_name->length);
7157 DBUG_ASSERT(record);
7158 hash_delete(&ndb_tables, record);
7159 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
7160 ER_TABLE_EXISTS_ERROR,
7161 "Local table %s.%s shadows ndb table",
7162 db, file_name->str);
7164 continue;
7166 if (file_on_disk)
7168 // File existed in NDB and as frm file, put in ok_tables list
7169 my_hash_insert(&ok_tables, (uchar*) file_name->str);
7170 continue;
7172 DBUG_PRINT("info", ("%s existed on disk", name));
7173 // The .ndb file exists on disk, but it's not in list of tables in ndb
7174 // Verify that handler agrees table is gone.
7175 if (ndbcluster_table_exists_in_engine(hton, thd, db, file_name->str) ==
7176 HA_ERR_NO_SUCH_TABLE)
7178 DBUG_PRINT("info", ("NDB says %s does not exists", file_name->str));
7179 it.remove();
7180 // Put in list of tables to remove from disk
7181 delete_list.push_back(thd->strdup(file_name->str));
7185 #ifdef HAVE_NDB_BINLOG
7186 /* setup logging to binlog for all discovered tables */
7188 char *end, *end1= name +
7189 build_table_filename(name, sizeof(name) - 1, db, "", "", 0);
7190 for (i= 0; i < ok_tables.records; i++)
7192 file_name_str= (char*)hash_element(&ok_tables, i);
7193 end= end1 +
7194 tablename_to_filename(file_name_str, end1, sizeof(name) - (end1 - name));
7195 pthread_mutex_lock(&LOCK_open);
7196 ndbcluster_create_binlog_setup(ndb, name, end-name,
7197 db, file_name_str, TRUE);
7198 pthread_mutex_unlock(&LOCK_open);
7201 #endif
7203 // Check for new files to discover
7204 DBUG_PRINT("info", ("Checking for new files to discover"));
7205 List<char> create_list;
7206 for (i= 0 ; i < ndb_tables.records ; i++)
7208 file_name_str= (char*) hash_element(&ndb_tables, i);
7209 if (!hash_search(&ok_tables, (uchar*) file_name_str, strlen(file_name_str)))
7211 build_table_filename(name, sizeof(name) - 1,
7212 db, file_name_str, reg_ext, 0);
7213 if (my_access(name, F_OK))
7215 DBUG_PRINT("info", ("%s must be discovered", file_name_str));
7216 // File is in list of ndb tables and not in ok_tables
7217 // This table need to be created
7218 create_list.push_back(thd->strdup(file_name_str));
7223 if (!global_read_lock)
7225 // Delete old files
7226 List_iterator_fast<char> it3(delete_list);
7227 while ((file_name_str= it3++))
7229 DBUG_PRINT("info", ("Remove table %s/%s", db, file_name_str));
7230 // Delete the table and all related files
7231 TABLE_LIST table_list;
7232 bzero((char*) &table_list,sizeof(table_list));
7233 table_list.db= (char*) db;
7234 table_list.alias= table_list.table_name= (char*)file_name_str;
7235 (void)mysql_rm_table_part2(thd, &table_list,
7236 FALSE, /* if_exists */
7237 FALSE, /* drop_temporary */
7238 FALSE, /* drop_view */
7239 TRUE /* dont_log_query*/);
7241 /* Clear error message that is returned when table is deleted */
7242 thd->clear_error();
7246 pthread_mutex_lock(&LOCK_open);
7247 // Create new files
7248 List_iterator_fast<char> it2(create_list);
7249 while ((file_name_str=it2++))
7251 DBUG_PRINT("info", ("Table %s need discovery", file_name_str));
7252 if (ndb_create_table_from_engine(thd, db, file_name_str) == 0)
7254 LEX_STRING *tmp_file_name= 0;
7255 tmp_file_name= thd->make_lex_string(tmp_file_name, file_name_str,
7256 strlen(file_name_str), TRUE);
7257 files->push_back(tmp_file_name);
7261 pthread_mutex_unlock(&LOCK_open);
7263 hash_free(&ok_tables);
7264 hash_free(&ndb_tables);
7266 // Delete schema file from files
7267 if (!strcmp(db, NDB_REP_DB))
7269 uint count = 0;
7270 while (count++ < files->elements)
7272 file_name = (LEX_STRING *)files->pop();
7273 if (!strcmp(file_name->str, NDB_SCHEMA_TABLE))
7275 DBUG_PRINT("info", ("skip %s.%s table, it should be hidden to user",
7276 NDB_REP_DB, NDB_SCHEMA_TABLE));
7277 continue;
7279 files->push_back(file_name);
7282 } // extra bracket to avoid gcc 2.95.3 warning
7283 DBUG_RETURN(0);
7288 Initialise all gloal variables before creating
7289 a NDB Cluster table handler
7292 /* Call back after cluster connect */
7293 static int connect_callback()
7295 pthread_mutex_lock(&LOCK_ndb_util_thread);
7296 update_status_variables(g_ndb_cluster_connection);
7298 uint node_id, i= 0;
7299 Ndb_cluster_connection_node_iter node_iter;
7300 memset((void *)g_node_id_map, 0xFFFF, sizeof(g_node_id_map));
7301 while ((node_id= g_ndb_cluster_connection->get_next_node(node_iter)))
7302 g_node_id_map[node_id]= i++;
7304 pthread_cond_signal(&COND_ndb_util_thread);
7305 pthread_mutex_unlock(&LOCK_ndb_util_thread);
7306 return 0;
7309 extern int ndb_dictionary_is_mysqld;
7310 extern pthread_mutex_t LOCK_plugin;
7312 static int ndbcluster_init(void *p)
7314 int res;
7315 DBUG_ENTER("ndbcluster_init");
7317 if (ndbcluster_inited)
7318 DBUG_RETURN(FALSE);
7320 pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
7321 pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
7322 pthread_cond_init(&COND_ndb_util_thread, NULL);
7323 pthread_cond_init(&COND_ndb_util_ready, NULL);
7324 ndb_util_thread_running= -1;
7325 ndbcluster_terminating= 0;
7326 ndb_dictionary_is_mysqld= 1;
7327 ndbcluster_hton= (handlerton *)p;
7330 handlerton *h= ndbcluster_hton;
7331 h->state= SHOW_OPTION_YES;
7332 h->db_type= DB_TYPE_NDBCLUSTER;
7333 h->close_connection= ndbcluster_close_connection;
7334 h->commit= ndbcluster_commit;
7335 h->rollback= ndbcluster_rollback;
7336 h->create= ndbcluster_create_handler; /* Create a new handler */
7337 h->drop_database= ndbcluster_drop_database; /* Drop a database */
7338 h->panic= ndbcluster_end; /* Panic call */
7339 h->show_status= ndbcluster_show_status; /* Show status */
7340 h->alter_tablespace= ndbcluster_alter_tablespace; /* Show status */
7341 h->partition_flags= ndbcluster_partition_flags; /* Partition flags */
7342 h->alter_table_flags=ndbcluster_alter_table_flags; /* Alter table flags */
7343 h->fill_files_table= ndbcluster_fill_files_table;
7344 #ifdef HAVE_NDB_BINLOG
7345 ndbcluster_binlog_init_handlerton();
7346 #endif
7347 h->flags= HTON_CAN_RECREATE | HTON_TEMPORARY_NOT_SUPPORTED;
7348 h->discover= ndbcluster_discover;
7349 h->find_files= ndbcluster_find_files;
7350 h->table_exists_in_engine= ndbcluster_table_exists_in_engine;
7353 // Initialize ndb interface
7354 ndb_init_internal();
7356 // Set connectstring if specified
7357 if (opt_ndbcluster_connectstring != 0)
7358 DBUG_PRINT("connectstring", ("%s", opt_ndbcluster_connectstring));
7359 if ((g_ndb_cluster_connection=
7360 new Ndb_cluster_connection(opt_ndbcluster_connectstring)) == 0)
7362 DBUG_PRINT("error",("Ndb_cluster_connection(%s)",
7363 opt_ndbcluster_connectstring));
7364 my_errno= HA_ERR_OUT_OF_MEM;
7365 goto ndbcluster_init_error;
7368 char buf[128];
7369 my_snprintf(buf, sizeof(buf), "mysqld --server-id=%lu", server_id);
7370 g_ndb_cluster_connection->set_name(buf);
7372 g_ndb_cluster_connection->set_optimized_node_selection
7373 (opt_ndb_optimized_node_selection);
7375 // Create a Ndb object to open the connection to NDB
7376 if ( (g_ndb= new Ndb(g_ndb_cluster_connection, "sys")) == 0 )
7378 DBUG_PRINT("error", ("failed to create global ndb object"));
7379 my_errno= HA_ERR_OUT_OF_MEM;
7380 goto ndbcluster_init_error;
7382 if (g_ndb->init() != 0)
7384 ERR_PRINT (g_ndb->getNdbError());
7385 goto ndbcluster_init_error;
7388 if ((res= g_ndb_cluster_connection->connect(0,0,0)) == 0)
7390 connect_callback();
7391 DBUG_PRINT("info",("NDBCLUSTER storage engine at %s on port %d",
7392 g_ndb_cluster_connection->get_connected_host(),
7393 g_ndb_cluster_connection->get_connected_port()));
7394 g_ndb_cluster_connection->wait_until_ready(10,3);
7396 else if (res == 1)
7398 if (g_ndb_cluster_connection->start_connect_thread(connect_callback))
7400 DBUG_PRINT("error", ("g_ndb_cluster_connection->start_connect_thread()"));
7401 goto ndbcluster_init_error;
7403 #ifndef DBUG_OFF
7405 char buf[1024];
7406 DBUG_PRINT("info",
7407 ("NDBCLUSTER storage engine not started, "
7408 "will connect using %s",
7409 g_ndb_cluster_connection->
7410 get_connectstring(buf,sizeof(buf))));
7412 #endif
7414 else
7416 DBUG_ASSERT(res == -1);
7417 DBUG_PRINT("error", ("permanent error"));
7418 goto ndbcluster_init_error;
7421 (void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0,
7422 (hash_get_key) ndbcluster_get_key,0,0);
7423 #ifdef HAVE_NDB_BINLOG
7424 /* start the ndb injector thread */
7425 if (ndbcluster_binlog_start())
7426 goto ndbcluster_init_error;
7427 #endif /* HAVE_NDB_BINLOG */
7429 ndb_cache_check_time = opt_ndb_cache_check_time;
7430 // Create utility thread
7431 pthread_t tmp;
7432 if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0))
7434 DBUG_PRINT("error", ("Could not create ndb utility thread"));
7435 hash_free(&ndbcluster_open_tables);
7436 pthread_mutex_destroy(&ndbcluster_mutex);
7437 pthread_mutex_destroy(&LOCK_ndb_util_thread);
7438 pthread_cond_destroy(&COND_ndb_util_thread);
7439 pthread_cond_destroy(&COND_ndb_util_ready);
7440 goto ndbcluster_init_error;
7443 /* Wait for the util thread to start */
7444 pthread_mutex_lock(&LOCK_ndb_util_thread);
7445 while (ndb_util_thread_running < 0)
7446 pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
7447 pthread_mutex_unlock(&LOCK_ndb_util_thread);
7449 if (!ndb_util_thread_running)
7451 DBUG_PRINT("error", ("ndb utility thread exited prematurely"));
7452 hash_free(&ndbcluster_open_tables);
7453 pthread_mutex_destroy(&ndbcluster_mutex);
7454 pthread_mutex_destroy(&LOCK_ndb_util_thread);
7455 pthread_cond_destroy(&COND_ndb_util_thread);
7456 pthread_cond_destroy(&COND_ndb_util_ready);
7457 goto ndbcluster_init_error;
7460 ndbcluster_inited= 1;
7461 DBUG_RETURN(FALSE);
7463 ndbcluster_init_error:
7464 if (g_ndb)
7465 delete g_ndb;
7466 g_ndb= NULL;
7467 if (g_ndb_cluster_connection)
7468 delete g_ndb_cluster_connection;
7469 g_ndb_cluster_connection= NULL;
7470 ndbcluster_hton->state= SHOW_OPTION_DISABLED; // If we couldn't use handler
7472 DBUG_RETURN(TRUE);
7475 static int ndbcluster_end(handlerton *hton, ha_panic_function type)
7477 DBUG_ENTER("ndbcluster_end");
7479 if (!ndbcluster_inited)
7480 DBUG_RETURN(0);
7481 ndbcluster_inited= 0;
7483 /* wait for util thread to finish */
7484 sql_print_information("Stopping Cluster Utility thread");
7485 pthread_mutex_lock(&LOCK_ndb_util_thread);
7486 ndbcluster_terminating= 1;
7487 pthread_cond_signal(&COND_ndb_util_thread);
7488 while (ndb_util_thread_running > 0)
7489 pthread_cond_wait(&COND_ndb_util_ready, &LOCK_ndb_util_thread);
7490 pthread_mutex_unlock(&LOCK_ndb_util_thread);
7493 #ifdef HAVE_NDB_BINLOG
7495 pthread_mutex_lock(&ndbcluster_mutex);
7496 while (ndbcluster_open_tables.records)
7498 NDB_SHARE *share=
7499 (NDB_SHARE*) hash_element(&ndbcluster_open_tables, 0);
7500 #ifndef DBUG_OFF
7501 fprintf(stderr, "NDB: table share %s with use_count %d not freed\n",
7502 share->key, share->use_count);
7503 #endif
7504 ndbcluster_real_free_share(&share);
7506 pthread_mutex_unlock(&ndbcluster_mutex);
7508 #endif
7509 hash_free(&ndbcluster_open_tables);
7511 if (g_ndb)
7513 #ifndef DBUG_OFF
7514 Ndb::Free_list_usage tmp;
7515 tmp.m_name= 0;
7516 while (g_ndb->get_free_list_usage(&tmp))
7518 uint leaked= (uint) tmp.m_created - tmp.m_free;
7519 if (leaked)
7520 fprintf(stderr, "NDB: Found %u %s%s that %s not been released\n",
7521 leaked, tmp.m_name,
7522 (leaked == 1)?"":"'s",
7523 (leaked == 1)?"has":"have");
7525 #endif
7526 delete g_ndb;
7527 g_ndb= NULL;
7529 delete g_ndb_cluster_connection;
7530 g_ndb_cluster_connection= NULL;
7532 // cleanup ndb interface
7533 ndb_end_internal();
7535 pthread_mutex_destroy(&ndbcluster_mutex);
7536 pthread_mutex_destroy(&LOCK_ndb_util_thread);
7537 pthread_cond_destroy(&COND_ndb_util_thread);
7538 pthread_cond_destroy(&COND_ndb_util_ready);
7539 DBUG_RETURN(0);
7542 void ha_ndbcluster::print_error(int error, myf errflag)
7544 DBUG_ENTER("ha_ndbcluster::print_error");
7545 DBUG_PRINT("enter", ("error: %d", error));
7547 if (error == HA_ERR_NO_PARTITION_FOUND)
7548 m_part_info->print_no_partition_found(table);
7549 else
7550 handler::print_error(error, errflag);
7551 DBUG_VOID_RETURN;
7556 Static error print function called from static handler method
7557 ndbcluster_commit and ndbcluster_rollback.
7560 void ndbcluster_print_error(int error, const NdbOperation *error_op)
7562 DBUG_ENTER("ndbcluster_print_error");
7563 TABLE_SHARE share;
7564 const char *tab_name= (error_op) ? error_op->getTableName() : "";
7565 share.db.str= (char*) "";
7566 share.db.length= 0;
7567 share.table_name.str= (char *) tab_name;
7568 share.table_name.length= strlen(tab_name);
7569 ha_ndbcluster error_handler(ndbcluster_hton, &share);
7570 error_handler.print_error(error, MYF(0));
7571 DBUG_VOID_RETURN;
7575 Set a given location from full pathname to database name.
7578 void ha_ndbcluster::set_dbname(const char *path_name, char *dbname)
7580 char *end, *ptr, *tmp_name;
7581 char tmp_buff[FN_REFLEN + 1];
7583 tmp_name= tmp_buff;
7584 /* Scan name from the end */
7585 ptr= strend(path_name)-1;
7586 while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
7587 ptr--;
7589 ptr--;
7590 end= ptr;
7591 while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
7592 ptr--;
7594 uint name_len= end - ptr;
7595 memcpy(tmp_name, ptr + 1, name_len);
7596 tmp_name[name_len]= '\0';
7597 #ifdef __WIN__
7598 /* Put to lower case */
7600 ptr= tmp_name;
7602 while (*ptr != '\0') {
7603 *ptr= tolower(*ptr);
7604 ptr++;
7606 #endif
7607 filename_to_tablename(tmp_name, dbname, sizeof(tmp_buff) - 1);
7611 Set m_dbname from full pathname to table file.
7614 void ha_ndbcluster::set_dbname(const char *path_name)
7616 set_dbname(path_name, m_dbname);
7620 Set a given location from full pathname to table file.
7623 void
7624 ha_ndbcluster::set_tabname(const char *path_name, char * tabname)
7626 char *end, *ptr, *tmp_name;
7627 char tmp_buff[FN_REFLEN + 1];
7629 tmp_name= tmp_buff;
7630 /* Scan name from the end */
7631 end= strend(path_name)-1;
7632 ptr= end;
7633 while (ptr >= path_name && *ptr != '\\' && *ptr != '/') {
7634 ptr--;
7636 uint name_len= end - ptr;
7637 memcpy(tmp_name, ptr + 1, end - ptr);
7638 tmp_name[name_len]= '\0';
7639 #ifdef __WIN__
7640 /* Put to lower case */
7641 ptr= tmp_name;
7643 while (*ptr != '\0') {
7644 *ptr= tolower(*ptr);
7645 ptr++;
7647 #endif
7648 filename_to_tablename(tmp_name, tabname, sizeof(tmp_buff) - 1);
7652 Set m_tabname from full pathname to table file.
7655 void ha_ndbcluster::set_tabname(const char *path_name)
7657 set_tabname(path_name, m_tabname);
7661 ha_rows
7662 ha_ndbcluster::records_in_range(uint inx, key_range *min_key,
7663 key_range *max_key)
7665 KEY *key_info= table->key_info + inx;
7666 uint key_length= key_info->key_length;
7667 NDB_INDEX_TYPE idx_type= get_index_type(inx);
7669 DBUG_ENTER("records_in_range");
7670 // Prevent partial read of hash indexes by returning HA_POS_ERROR
7671 if ((idx_type == UNIQUE_INDEX || idx_type == PRIMARY_KEY_INDEX) &&
7672 ((min_key && min_key->length < key_length) ||
7673 (max_key && max_key->length < key_length)))
7674 DBUG_RETURN(HA_POS_ERROR);
7676 // Read from hash index with full key
7677 // This is a "const" table which returns only one record!
7678 if ((idx_type != ORDERED_INDEX) &&
7679 ((min_key && min_key->length == key_length) ||
7680 (max_key && max_key->length == key_length)))
7681 DBUG_RETURN(1);
7683 if ((idx_type == PRIMARY_KEY_ORDERED_INDEX ||
7684 idx_type == UNIQUE_ORDERED_INDEX ||
7685 idx_type == ORDERED_INDEX) &&
7686 m_index[inx].index_stat != NULL)
7688 NDB_INDEX_DATA& d=m_index[inx];
7689 const NDBINDEX* index= d.index;
7690 Ndb* ndb=get_ndb();
7691 NdbTransaction* trans=NULL;
7692 NdbIndexScanOperation* op=NULL;
7693 int res=0;
7694 Uint64 rows;
7698 // We must provide approx table rows
7699 Uint64 table_rows=0;
7700 Ndb_local_table_statistics *ndb_info= m_table_info;
7701 if (ndb_info->records != ~(ha_rows)0 && ndb_info->records != 0)
7703 table_rows = ndb_info->records;
7704 DBUG_PRINT("info", ("use info->records: %lu", (ulong) table_rows));
7706 else
7708 Ndb_statistics stat;
7709 if ((res=ndb_get_table_statistics(this, TRUE, ndb, m_table, &stat)))
7710 break;
7711 table_rows=stat.row_count;
7712 DBUG_PRINT("info", ("use db row_count: %lu", (ulong) table_rows));
7713 if (table_rows == 0) {
7714 // Problem if autocommit=0
7715 #ifdef ndb_get_table_statistics_uses_active_trans
7716 rows=0;
7717 break;
7718 #endif
7722 // Define scan op for the range
7723 if ((trans=m_active_trans) == NULL ||
7724 trans->commitStatus() != NdbTransaction::Started)
7726 DBUG_PRINT("info", ("no active trans"));
7727 if (! (trans=ndb->startTransaction()))
7728 ERR_BREAK(ndb->getNdbError(), res);
7730 if (! (op=trans->getNdbIndexScanOperation(index, (NDBTAB*)m_table)))
7731 ERR_BREAK(trans->getNdbError(), res);
7732 if ((op->readTuples(NdbOperation::LM_CommittedRead)) == -1)
7733 ERR_BREAK(op->getNdbError(), res);
7734 const key_range *keys[2]={ min_key, max_key };
7735 if ((res=set_bounds(op, inx, TRUE, keys)) != 0)
7736 break;
7738 // Decide if db should be contacted
7739 int flags=0;
7740 if (d.index_stat_query_count < d.index_stat_cache_entries ||
7741 (d.index_stat_update_freq != 0 &&
7742 d.index_stat_query_count % d.index_stat_update_freq == 0))
7744 DBUG_PRINT("info", ("force stat from db"));
7745 flags|=NdbIndexStat::RR_UseDb;
7747 if (d.index_stat->records_in_range(index, op, table_rows, &rows, flags) == -1)
7748 ERR_BREAK(d.index_stat->getNdbError(), res);
7749 d.index_stat_query_count++;
7750 } while (0);
7752 if (trans != m_active_trans && rows == 0)
7753 rows = 1;
7754 if (trans != m_active_trans && trans != NULL)
7755 ndb->closeTransaction(trans);
7756 if (res != 0)
7757 DBUG_RETURN(HA_POS_ERROR);
7758 DBUG_RETURN(rows);
7761 DBUG_RETURN(10); /* Good guess when you don't know anything */
7764 ulonglong ha_ndbcluster::table_flags(void) const
7766 THD *thd= current_thd;
7767 ulonglong f= m_table_flags;
7768 if (m_ha_not_exact_count)
7769 f= f & ~HA_STATS_RECORDS_IS_EXACT;
7771 To allow for logging of ndb tables during stmt based logging;
7772 flag cabablity, but also turn off flag for OWN_BINLOGGING
7774 if (thd->variables.binlog_format == BINLOG_FORMAT_STMT)
7775 f= (f | HA_BINLOG_STMT_CAPABLE) & ~HA_HAS_OWN_BINLOGGING;
7776 return f;
7778 const char * ha_ndbcluster::table_type() const
7780 return("NDBCLUSTER");
7782 uint ha_ndbcluster::max_supported_record_length() const
7784 return NDB_MAX_TUPLE_SIZE;
7786 uint ha_ndbcluster::max_supported_keys() const
7788 return MAX_KEY;
7790 uint ha_ndbcluster::max_supported_key_parts() const
7792 return NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
7794 uint ha_ndbcluster::max_supported_key_length() const
7796 return NDB_MAX_KEY_SIZE;
7798 uint ha_ndbcluster::max_supported_key_part_length() const
7800 return NDB_MAX_KEY_SIZE;
7802 bool ha_ndbcluster::low_byte_first() const
7804 #ifdef WORDS_BIGENDIAN
7805 return FALSE;
7806 #else
7807 return TRUE;
7808 #endif
7810 const char* ha_ndbcluster::index_type(uint key_number)
7812 switch (get_index_type(key_number)) {
7813 case ORDERED_INDEX:
7814 case UNIQUE_ORDERED_INDEX:
7815 case PRIMARY_KEY_ORDERED_INDEX:
7816 return "BTREE";
7817 case UNIQUE_INDEX:
7818 case PRIMARY_KEY_INDEX:
7819 default:
7820 return "HASH";
7824 uint8 ha_ndbcluster::table_cache_type()
7826 DBUG_ENTER("ha_ndbcluster::table_cache_type=HA_CACHE_TBL_ASKTRANSACT");
7827 DBUG_RETURN(HA_CACHE_TBL_ASKTRANSACT);
7831 uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
7832 Uint64 *commit_count)
7834 char name[FN_REFLEN + 1];
7835 NDB_SHARE *share;
7836 DBUG_ENTER("ndb_get_commitcount");
7838 build_table_filename(name, sizeof(name) - 1,
7839 dbname, tabname, "", 0);
7840 DBUG_PRINT("enter", ("name: %s", name));
7841 pthread_mutex_lock(&ndbcluster_mutex);
7842 if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
7843 (uchar*) name,
7844 strlen(name))))
7846 pthread_mutex_unlock(&ndbcluster_mutex);
7847 DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables", name));
7848 DBUG_RETURN(1);
7850 /* ndb_share reference temporary, free below */
7851 share->use_count++;
7852 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
7853 share->key, share->use_count));
7854 pthread_mutex_unlock(&ndbcluster_mutex);
7856 pthread_mutex_lock(&share->mutex);
7857 if (ndb_cache_check_time > 0)
7859 if (share->commit_count != 0)
7861 *commit_count= share->commit_count;
7862 #ifndef DBUG_OFF
7863 char buff[22];
7864 #endif
7865 DBUG_PRINT("info", ("Getting commit_count: %s from share",
7866 llstr(share->commit_count, buff)));
7867 pthread_mutex_unlock(&share->mutex);
7868 /* ndb_share reference temporary free */
7869 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
7870 share->key, share->use_count));
7871 free_share(&share);
7872 DBUG_RETURN(0);
7875 DBUG_PRINT("info", ("Get commit_count from NDB"));
7876 Ndb *ndb;
7877 if (!(ndb= check_ndb_in_thd(thd)))
7878 DBUG_RETURN(1);
7879 if (ndb->setDatabaseName(dbname))
7881 ERR_RETURN(ndb->getNdbError());
7883 uint lock= share->commit_count_lock;
7884 pthread_mutex_unlock(&share->mutex);
7886 struct Ndb_statistics stat;
7888 Ndb_table_guard ndbtab_g(ndb->getDictionary(), tabname);
7889 if (ndbtab_g.get_table() == 0
7890 || ndb_get_table_statistics(NULL, FALSE, ndb, ndbtab_g.get_table(), &stat))
7892 /* ndb_share reference temporary free */
7893 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
7894 share->key, share->use_count));
7895 free_share(&share);
7896 DBUG_RETURN(1);
7900 pthread_mutex_lock(&share->mutex);
7901 if (share->commit_count_lock == lock)
7903 #ifndef DBUG_OFF
7904 char buff[22];
7905 #endif
7906 DBUG_PRINT("info", ("Setting commit_count to %s",
7907 llstr(stat.commit_count, buff)));
7908 share->commit_count= stat.commit_count;
7909 *commit_count= stat.commit_count;
7911 else
7913 DBUG_PRINT("info", ("Discarding commit_count, comit_count_lock changed"));
7914 *commit_count= 0;
7916 pthread_mutex_unlock(&share->mutex);
7917 /* ndb_share reference temporary free */
7918 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
7919 share->key, share->use_count));
7920 free_share(&share);
7921 DBUG_RETURN(0);
7926 Check if a cached query can be used.
7928 This is done by comparing the supplied engine_data to commit_count of
7929 the table.
7931 The commit_count is either retrieved from the share for the table, where
7932 it has been cached by the util thread. If the util thread is not started,
7933 NDB has to be contacetd to retrieve the commit_count, this will introduce
7934 a small delay while waiting for NDB to answer.
7937 @param thd thread handle
7938 @param full_name concatenation of database name,
7939 the null character '\\0', and the table name
7940 @param full_name_len length of the full name,
7941 i.e. len(dbname) + len(tablename) + 1
7942 @param engine_data parameter retrieved when query was first inserted into
7943 the cache. If the value of engine_data is changed,
7944 all queries for this table should be invalidated.
7946 @retval
7947 TRUE Yes, use the query from cache
7948 @retval
7949 FALSE No, don't use the cached query, and if engine_data
7950 has changed, all queries for this table should be invalidated
7954 static my_bool
7955 ndbcluster_cache_retrieval_allowed(THD *thd,
7956 char *full_name, uint full_name_len,
7957 ulonglong *engine_data)
7959 Uint64 commit_count;
7960 bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
7961 char *dbname= full_name;
7962 char *tabname= dbname+strlen(dbname)+1;
7963 #ifndef DBUG_OFF
7964 char buff[22], buff2[22];
7965 #endif
7966 DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
7967 DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
7968 dbname, tabname, is_autocommit));
7970 if (!is_autocommit)
7972 DBUG_PRINT("exit", ("No, don't use cache in transaction"));
7973 DBUG_RETURN(FALSE);
7976 if (ndb_get_commitcount(thd, dbname, tabname, &commit_count))
7978 *engine_data= 0; /* invalidate */
7979 DBUG_PRINT("exit", ("No, could not retrieve commit_count"));
7980 DBUG_RETURN(FALSE);
7982 DBUG_PRINT("info", ("*engine_data: %s, commit_count: %s",
7983 llstr(*engine_data, buff), llstr(commit_count, buff2)));
7984 if (commit_count == 0)
7986 *engine_data= 0; /* invalidate */
7987 DBUG_PRINT("exit", ("No, local commit has been performed"));
7988 DBUG_RETURN(FALSE);
7990 else if (*engine_data != commit_count)
7992 *engine_data= commit_count; /* invalidate */
7993 DBUG_PRINT("exit", ("No, commit_count has changed"));
7994 DBUG_RETURN(FALSE);
7997 DBUG_PRINT("exit", ("OK to use cache, engine_data: %s",
7998 llstr(*engine_data, buff)));
7999 DBUG_RETURN(TRUE);
8004 Register a table for use in the query cache.
8006 Fetch the commit_count for the table and return it in engine_data,
8007 this will later be used to check if the table has changed, before
8008 the cached query is reused.
8010 @param thd thread handle
8011 @param full_name concatenation of database name,
8012 the null character '\\0', and the table name
8013 @param full_name_len length of the full name,
8014 i.e. len(dbname) + len(tablename) + 1
8015 @param engine_callback function to be called before using cache on
8016 this table
8017 @param[out] engine_data commit_count for this table
8019 @retval
8020 TRUE Yes, it's ok to cahce this query
8021 @retval
8022 FALSE No, don't cach the query
8025 my_bool
8026 ha_ndbcluster::register_query_cache_table(THD *thd,
8027 char *full_name, uint full_name_len,
8028 qc_engine_callback *engine_callback,
8029 ulonglong *engine_data)
8031 Uint64 commit_count;
8032 #ifndef DBUG_OFF
8033 char buff[22];
8034 #endif
8035 bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
8036 DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
8037 DBUG_PRINT("enter",("dbname: %s, tabname: %s, is_autocommit: %d",
8038 m_dbname, m_tabname, is_autocommit));
8040 if (!is_autocommit)
8042 DBUG_PRINT("exit", ("Can't register table during transaction"));
8043 DBUG_RETURN(FALSE);
8046 if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count))
8048 *engine_data= 0;
8049 DBUG_PRINT("exit", ("Error, could not get commitcount"));
8050 DBUG_RETURN(FALSE);
8052 *engine_data= commit_count;
8053 *engine_callback= ndbcluster_cache_retrieval_allowed;
8054 DBUG_PRINT("exit", ("commit_count: %s", llstr(commit_count, buff)));
8055 DBUG_RETURN(commit_count > 0);
8060 Handling the shared NDB_SHARE structure that is needed to
8061 provide table locking.
8063 It's also used for sharing data with other NDB handlers
8064 in the same MySQL Server. There is currently not much
8065 data we want to or can share.
8068 static uchar *ndbcluster_get_key(NDB_SHARE *share, size_t *length,
8069 my_bool not_used __attribute__((unused)))
8071 *length= share->key_length;
8072 return (uchar*) share->key;
8076 #ifndef DBUG_OFF
8078 static void print_share(const char* where, NDB_SHARE* share)
8080 fprintf(DBUG_FILE,
8081 "%s %s.%s: use_count: %u, commit_count: %lu\n",
8082 where, share->db, share->table_name, share->use_count,
8083 (ulong) share->commit_count);
8084 fprintf(DBUG_FILE,
8085 " - key: %s, key_length: %d\n",
8086 share->key, share->key_length);
8088 #ifdef HAVE_NDB_BINLOG
8089 if (share->table)
8090 fprintf(DBUG_FILE,
8091 " - share->table: %p %s.%s\n",
8092 share->table, share->table->s->db.str,
8093 share->table->s->table_name.str);
8094 #endif
8098 static void print_ndbcluster_open_tables()
8100 DBUG_LOCK_FILE;
8101 fprintf(DBUG_FILE, ">ndbcluster_open_tables\n");
8102 for (uint i= 0; i < ndbcluster_open_tables.records; i++)
8103 print_share("",
8104 (NDB_SHARE*)hash_element(&ndbcluster_open_tables, i));
8105 fprintf(DBUG_FILE, "<ndbcluster_open_tables\n");
8106 DBUG_UNLOCK_FILE;
8109 #endif
8112 #define dbug_print_open_tables() \
8113 DBUG_EXECUTE("info", \
8114 print_ndbcluster_open_tables(););
8116 #define dbug_print_share(t, s) \
8117 DBUG_LOCK_FILE; \
8118 DBUG_EXECUTE("info", \
8119 print_share((t), (s));); \
8120 DBUG_UNLOCK_FILE;
8123 #ifdef HAVE_NDB_BINLOG
8125 For some reason a share is still around, try to salvage the situation
8126 by closing all cached tables. If the share still exists, there is an
8127 error somewhere but only report this to the error log. Keep this
8128 "trailing share" but rename it since there are still references to it
8129 to avoid segmentation faults. There is a risk that the memory for
8130 this trailing share leaks.
8132 Must be called with previous pthread_mutex_lock(&ndbcluster_mutex)
8134 int handle_trailing_share(NDB_SHARE *share)
8136 THD *thd= current_thd;
8137 static ulong trailing_share_id= 0;
8138 DBUG_ENTER("handle_trailing_share");
8140 /* ndb_share reference temporary, free below */
8141 ++share->use_count;
8142 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
8143 share->key, share->use_count));
8144 pthread_mutex_unlock(&ndbcluster_mutex);
8146 TABLE_LIST table_list;
8147 bzero((char*) &table_list,sizeof(table_list));
8148 table_list.db= share->db;
8149 table_list.alias= table_list.table_name= share->table_name;
8150 safe_mutex_assert_owner(&LOCK_open);
8151 close_cached_tables(thd, &table_list, TRUE, FALSE, FALSE);
8153 pthread_mutex_lock(&ndbcluster_mutex);
8154 /* ndb_share reference temporary free */
8155 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
8156 share->key, share->use_count));
8157 if (!--share->use_count)
8159 if (ndb_extra_logging)
8160 sql_print_information("NDB_SHARE: trailing share "
8161 "%s(connect_count: %u) "
8162 "released by close_cached_tables at "
8163 "connect_count: %u",
8164 share->key,
8165 share->connect_count,
8166 g_ndb_cluster_connection->get_connect_count());
8167 ndbcluster_real_free_share(&share);
8168 DBUG_RETURN(0);
8172 share still exists, if share has not been dropped by server
8173 release that share
8175 if (share->state != NSS_DROPPED)
8177 share->state= NSS_DROPPED;
8178 /* ndb_share reference create free */
8179 DBUG_PRINT("NDB_SHARE", ("%s create free use_count: %u",
8180 share->key, share->use_count));
8181 --share->use_count;
8183 if (share->use_count == 0)
8185 if (ndb_extra_logging)
8186 sql_print_information("NDB_SHARE: trailing share "
8187 "%s(connect_count: %u) "
8188 "released after NSS_DROPPED check "
8189 "at connect_count: %u",
8190 share->key,
8191 share->connect_count,
8192 g_ndb_cluster_connection->get_connect_count());
8193 ndbcluster_real_free_share(&share);
8194 DBUG_RETURN(0);
8198 sql_print_warning("NDB_SHARE: %s already exists use_count=%d."
8199 " Moving away for safety, but possible memleak.",
8200 share->key, share->use_count);
8201 dbug_print_open_tables();
8204 Ndb share has not been released as it should
8206 #ifdef NOT_YET
8207 DBUG_ASSERT(FALSE);
8208 #endif
8211 This is probably an error. We can however save the situation
8212 at the cost of a possible mem leak, by "renaming" the share
8213 - First remove from hash
8215 hash_delete(&ndbcluster_open_tables, (uchar*) share);
8218 now give it a new name, just a running number
8219 if space is not enough allocate some more
8222 const uint min_key_length= 10;
8223 if (share->key_length < min_key_length)
8225 share->key= (char*) alloc_root(&share->mem_root, min_key_length + 1);
8226 share->key_length= min_key_length;
8228 share->key_length=
8229 my_snprintf(share->key, min_key_length + 1, "#leak%lu",
8230 trailing_share_id++);
8232 /* Keep it for possible the future trailing free */
8233 my_hash_insert(&ndbcluster_open_tables, (uchar*) share);
8235 DBUG_RETURN(0);
8239 Rename share is used during rename table.
8241 static int rename_share(NDB_SHARE *share, const char *new_key)
8243 NDB_SHARE *tmp;
8244 pthread_mutex_lock(&ndbcluster_mutex);
8245 uint new_length= (uint) strlen(new_key);
8246 DBUG_PRINT("rename_share", ("old_key: %s old__length: %d",
8247 share->key, share->key_length));
8248 if ((tmp= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
8249 (uchar*) new_key, new_length)))
8250 handle_trailing_share(tmp);
8252 /* remove the share from hash */
8253 hash_delete(&ndbcluster_open_tables, (uchar*) share);
8254 dbug_print_open_tables();
8256 /* save old stuff if insert should fail */
8257 uint old_length= share->key_length;
8258 char *old_key= share->key;
8261 now allocate and set the new key, db etc
8262 enough space for key, db, and table_name
8264 share->key= (char*) alloc_root(&share->mem_root, 2 * (new_length + 1));
8265 strmov(share->key, new_key);
8266 share->key_length= new_length;
8268 if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
8270 // ToDo free the allocated stuff above?
8271 DBUG_PRINT("error", ("rename_share: my_hash_insert %s failed",
8272 share->key));
8273 share->key= old_key;
8274 share->key_length= old_length;
8275 if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
8277 sql_print_error("rename_share: failed to recover %s", share->key);
8278 DBUG_PRINT("error", ("rename_share: my_hash_insert %s failed",
8279 share->key));
8281 dbug_print_open_tables();
8282 pthread_mutex_unlock(&ndbcluster_mutex);
8283 return -1;
8285 dbug_print_open_tables();
8287 share->db= share->key + new_length + 1;
8288 ha_ndbcluster::set_dbname(new_key, share->db);
8289 share->table_name= share->db + strlen(share->db) + 1;
8290 ha_ndbcluster::set_tabname(new_key, share->table_name);
8292 dbug_print_share("rename_share:", share);
8293 if (share->table)
8295 if (share->op == 0)
8297 share->table->s->db.str= share->db;
8298 share->table->s->db.length= strlen(share->db);
8299 share->table->s->table_name.str= share->table_name;
8300 share->table->s->table_name.length= strlen(share->table_name);
8303 /* else rename will be handled when the ALTER event comes */
8304 share->old_names= old_key;
8305 // ToDo free old_names after ALTER EVENT
8307 pthread_mutex_unlock(&ndbcluster_mutex);
8308 return 0;
8310 #endif
8313 Increase refcount on existing share.
8314 Always returns share and cannot fail.
8316 NDB_SHARE *ndbcluster_get_share(NDB_SHARE *share)
8318 pthread_mutex_lock(&ndbcluster_mutex);
8319 share->use_count++;
8321 dbug_print_open_tables();
8322 dbug_print_share("ndbcluster_get_share:", share);
8323 pthread_mutex_unlock(&ndbcluster_mutex);
8324 return share;
8329 Get a share object for key
8331 Returns share for key, and increases the refcount on the share.
8333 create_if_not_exists == TRUE:
8334 creates share if it does not alreade exist
8335 returns 0 only due to out of memory, and then sets my_error
8337 create_if_not_exists == FALSE:
8338 returns 0 if share does not exist
8340 have_lock == TRUE, pthread_mutex_lock(&ndbcluster_mutex) already taken
8343 NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table,
8344 bool create_if_not_exists,
8345 bool have_lock)
8347 NDB_SHARE *share;
8348 uint length= (uint) strlen(key);
8349 DBUG_ENTER("ndbcluster_get_share");
8350 DBUG_PRINT("enter", ("key: '%s'", key));
8352 if (!have_lock)
8353 pthread_mutex_lock(&ndbcluster_mutex);
8354 if (!(share= (NDB_SHARE*) hash_search(&ndbcluster_open_tables,
8355 (uchar*) key,
8356 length)))
8358 if (!create_if_not_exists)
8360 DBUG_PRINT("error", ("get_share: %s does not exist", key));
8361 if (!have_lock)
8362 pthread_mutex_unlock(&ndbcluster_mutex);
8363 DBUG_RETURN(0);
8365 if ((share= (NDB_SHARE*) my_malloc(sizeof(*share),
8366 MYF(MY_WME | MY_ZEROFILL))))
8368 MEM_ROOT **root_ptr=
8369 my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
8370 MEM_ROOT *old_root= *root_ptr;
8371 init_sql_alloc(&share->mem_root, 1024, 0);
8372 *root_ptr= &share->mem_root; // remember to reset before return
8373 share->state= NSS_INITIAL;
8374 /* enough space for key, db, and table_name */
8375 share->key= (char*) alloc_root(*root_ptr, 2 * (length + 1));
8376 share->key_length= length;
8377 strmov(share->key, key);
8378 if (my_hash_insert(&ndbcluster_open_tables, (uchar*) share))
8380 free_root(&share->mem_root, MYF(0));
8381 my_free((uchar*) share, 0);
8382 *root_ptr= old_root;
8383 if (!have_lock)
8384 pthread_mutex_unlock(&ndbcluster_mutex);
8385 DBUG_RETURN(0);
8387 thr_lock_init(&share->lock);
8388 pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
8389 share->commit_count= 0;
8390 share->commit_count_lock= 0;
8391 share->db= share->key + length + 1;
8392 ha_ndbcluster::set_dbname(key, share->db);
8393 share->table_name= share->db + strlen(share->db) + 1;
8394 ha_ndbcluster::set_tabname(key, share->table_name);
8395 #ifdef HAVE_NDB_BINLOG
8396 if (ndbcluster_binlog_init_share(share, table))
8398 DBUG_PRINT("error", ("get_share: %s could not init share", key));
8399 ndbcluster_real_free_share(&share);
8400 *root_ptr= old_root;
8401 if (!have_lock)
8402 pthread_mutex_unlock(&ndbcluster_mutex);
8403 DBUG_RETURN(0);
8405 #endif
8406 *root_ptr= old_root;
8408 else
8410 DBUG_PRINT("error", ("get_share: failed to alloc share"));
8411 if (!have_lock)
8412 pthread_mutex_unlock(&ndbcluster_mutex);
8413 my_error(ER_OUTOFMEMORY, MYF(0), static_cast<int>(sizeof(*share)));
8414 DBUG_RETURN(0);
8417 share->use_count++;
8419 dbug_print_open_tables();
8420 dbug_print_share("ndbcluster_get_share:", share);
8421 if (!have_lock)
8422 pthread_mutex_unlock(&ndbcluster_mutex);
8423 DBUG_RETURN(share);
8427 void ndbcluster_real_free_share(NDB_SHARE **share)
8429 DBUG_ENTER("ndbcluster_real_free_share");
8430 dbug_print_share("ndbcluster_real_free_share:", *share);
8432 hash_delete(&ndbcluster_open_tables, (uchar*) *share);
8433 thr_lock_delete(&(*share)->lock);
8434 pthread_mutex_destroy(&(*share)->mutex);
8436 #ifdef HAVE_NDB_BINLOG
8437 if ((*share)->table)
8439 // (*share)->table->mem_root is freed by closefrm
8440 closefrm((*share)->table, 0);
8441 // (*share)->table_share->mem_root is freed by free_table_share
8442 free_table_share((*share)->table_share);
8443 #ifndef DBUG_OFF
8444 bzero((uchar*)(*share)->table_share, sizeof(*(*share)->table_share));
8445 bzero((uchar*)(*share)->table, sizeof(*(*share)->table));
8446 (*share)->table_share= 0;
8447 (*share)->table= 0;
8448 #endif
8450 #endif
8451 free_root(&(*share)->mem_root, MYF(0));
8452 my_free((uchar*) *share, MYF(0));
8453 *share= 0;
8455 dbug_print_open_tables();
8456 DBUG_VOID_RETURN;
8460 void ndbcluster_free_share(NDB_SHARE **share, bool have_lock)
8462 if (!have_lock)
8463 pthread_mutex_lock(&ndbcluster_mutex);
8464 if ((*share)->util_lock == current_thd)
8465 (*share)->util_lock= 0;
8466 if (!--(*share)->use_count)
8468 ndbcluster_real_free_share(share);
8470 else
8472 dbug_print_open_tables();
8473 dbug_print_share("ndbcluster_free_share:", *share);
8475 if (!have_lock)
8476 pthread_mutex_unlock(&ndbcluster_mutex);
8480 static
8482 ndb_get_table_statistics(ha_ndbcluster* file, bool report_error, Ndb* ndb, const NDBTAB *ndbtab,
8483 struct Ndb_statistics * ndbstat)
8485 NdbTransaction* pTrans;
8486 NdbError error;
8487 int retries= 10;
8488 int reterr= 0;
8489 int retry_sleep= 30; /* 30 milliseconds, transaction */
8490 #ifndef DBUG_OFF
8491 char buff[22], buff2[22], buff3[22], buff4[22];
8492 #endif
8493 DBUG_ENTER("ndb_get_table_statistics");
8494 DBUG_PRINT("enter", ("table: %s", ndbtab->getName()));
8496 DBUG_ASSERT(ndbtab != 0);
8500 Uint64 rows, commits, fixed_mem, var_mem;
8501 Uint32 size;
8502 Uint32 count= 0;
8503 Uint64 sum_rows= 0;
8504 Uint64 sum_commits= 0;
8505 Uint64 sum_row_size= 0;
8506 Uint64 sum_mem= 0;
8507 NdbScanOperation*pOp;
8508 int check;
8510 if ((pTrans= ndb->startTransaction()) == NULL)
8512 error= ndb->getNdbError();
8513 goto retry;
8516 if ((pOp= pTrans->getNdbScanOperation(ndbtab)) == NULL)
8518 error= pTrans->getNdbError();
8519 goto retry;
8522 if (pOp->readTuples(NdbOperation::LM_CommittedRead))
8524 error= pOp->getNdbError();
8525 goto retry;
8528 if (pOp->interpret_exit_last_row() == -1)
8530 error= pOp->getNdbError();
8531 goto retry;
8534 pOp->getValue(NdbDictionary::Column::ROW_COUNT, (char*)&rows);
8535 pOp->getValue(NdbDictionary::Column::COMMIT_COUNT, (char*)&commits);
8536 pOp->getValue(NdbDictionary::Column::ROW_SIZE, (char*)&size);
8537 pOp->getValue(NdbDictionary::Column::FRAGMENT_FIXED_MEMORY,
8538 (char*)&fixed_mem);
8539 pOp->getValue(NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY,
8540 (char*)&var_mem);
8542 if (pTrans->execute(NdbTransaction::NoCommit,
8543 NdbOperation::AbortOnError,
8544 TRUE) == -1)
8546 error= pTrans->getNdbError();
8547 goto retry;
8550 while ((check= pOp->nextResult(TRUE, TRUE)) == 0)
8552 sum_rows+= rows;
8553 sum_commits+= commits;
8554 if (sum_row_size < size)
8555 sum_row_size= size;
8556 sum_mem+= fixed_mem + var_mem;
8557 count++;
8560 if (check == -1)
8562 error= pOp->getNdbError();
8563 goto retry;
8566 pOp->close(TRUE);
8568 ndb->closeTransaction(pTrans);
8570 ndbstat->row_count= sum_rows;
8571 ndbstat->commit_count= sum_commits;
8572 ndbstat->row_size= sum_row_size;
8573 ndbstat->fragment_memory= sum_mem;
8575 DBUG_PRINT("exit", ("records: %s commits: %s "
8576 "row_size: %s mem: %s count: %u",
8577 llstr(sum_rows, buff),
8578 llstr(sum_commits, buff2),
8579 llstr(sum_row_size, buff3),
8580 llstr(sum_mem, buff4),
8581 count));
8583 DBUG_RETURN(0);
8584 retry:
8585 if(report_error)
8587 if (file && pTrans)
8589 reterr= file->ndb_err(pTrans);
8591 else
8593 const NdbError& tmp= error;
8594 ERR_PRINT(tmp);
8595 reterr= ndb_to_mysql_error(&tmp);
8598 else
8599 reterr= error.code;
8601 if (pTrans)
8603 ndb->closeTransaction(pTrans);
8604 pTrans= NULL;
8606 if (error.status == NdbError::TemporaryError && retries--)
8608 my_sleep(retry_sleep);
8609 continue;
8611 set_ndb_err(current_thd, error);
8612 break;
8613 } while(1);
8614 DBUG_PRINT("exit", ("failed, reterr: %u, NdbError %u(%s)", reterr,
8615 error.code, error.message));
8616 DBUG_RETURN(reterr);
8620 Create a .ndb file to serve as a placeholder indicating
8621 that the table with this name is a ndb table.
8624 int ha_ndbcluster::write_ndb_file(const char *name)
8626 File file;
8627 bool error=1;
8628 char path[FN_REFLEN];
8630 DBUG_ENTER("write_ndb_file");
8631 DBUG_PRINT("enter", ("name: %s", name));
8633 (void)strxnmov(path, FN_REFLEN-1,
8634 mysql_data_home,"/",name,ha_ndb_ext,NullS);
8636 if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
8638 // It's an empty file
8639 error=0;
8640 my_close(file,MYF(0));
8642 DBUG_RETURN(error);
8645 void
8646 ha_ndbcluster::release_completed_operations(NdbTransaction *trans,
8647 bool force_release)
8649 if (trans->hasBlobOperation())
8651 /* We are reading/writing BLOB fields,
8652 releasing operation records is unsafe
8654 return;
8656 if (!force_release)
8658 if (get_thd_ndb(current_thd)->query_state & NDB_QUERY_MULTI_READ_RANGE)
8660 /* We are batching reads and have not consumed all fetched
8661 rows yet, releasing operation records is unsafe
8663 return;
8666 trans->releaseCompletedOperations();
8669 bool
8670 ha_ndbcluster::null_value_index_search(KEY_MULTI_RANGE *ranges,
8671 KEY_MULTI_RANGE *end_range,
8672 HANDLER_BUFFER *buffer)
8674 DBUG_ENTER("null_value_index_search");
8675 KEY* key_info= table->key_info + active_index;
8676 KEY_MULTI_RANGE *range= ranges;
8677 ulong reclength= table->s->reclength;
8678 uchar *curr= (uchar*)buffer->buffer;
8679 uchar *end_of_buffer= (uchar*)buffer->buffer_end;
8681 for (; range<end_range && curr+reclength <= end_of_buffer;
8682 range++)
8684 const uchar *key= range->start_key.key;
8685 uint key_len= range->start_key.length;
8686 if (check_null_in_key(key_info, key, key_len))
8687 DBUG_RETURN(TRUE);
8688 curr += reclength;
8690 DBUG_RETURN(FALSE);
8694 ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
8695 KEY_MULTI_RANGE *ranges,
8696 uint range_count,
8697 bool sorted,
8698 HANDLER_BUFFER *buffer)
8700 m_write_op= FALSE;
8701 int res;
8702 KEY* key_info= table->key_info + active_index;
8703 NDB_INDEX_TYPE cur_index_type= get_index_type(active_index);
8704 ulong reclength= table_share->reclength;
8705 NdbOperation* op;
8706 Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
8707 DBUG_ENTER("ha_ndbcluster::read_multi_range_first");
8710 * blobs and unique hash index with NULL can't be batched currently
8712 if (uses_blob_value() ||
8713 (cur_index_type == UNIQUE_INDEX &&
8714 has_null_in_unique_index(active_index) &&
8715 null_value_index_search(ranges, ranges+range_count, buffer))
8716 || m_delete_cannot_batch || m_update_cannot_batch)
8718 m_disable_multi_read= TRUE;
8719 DBUG_RETURN(handler::read_multi_range_first(found_range_p,
8720 ranges,
8721 range_count,
8722 sorted,
8723 buffer));
8725 thd_ndb->query_state|= NDB_QUERY_MULTI_READ_RANGE;
8726 m_disable_multi_read= FALSE;
8729 * Copy arguments into member variables
8731 m_multi_ranges= ranges;
8732 multi_range_curr= ranges;
8733 multi_range_end= ranges+range_count;
8734 multi_range_sorted= sorted;
8735 multi_range_buffer= buffer;
8738 * read multi range will read ranges as follows (if not ordered)
8740 * input read order
8741 * ====== ==========
8742 * pk-op 1 pk-op 1
8743 * pk-op 2 pk-op 2
8744 * range 3 range (3,5) NOTE result rows will be intermixed
8745 * pk-op 4 pk-op 4
8746 * range 5
8747 * pk-op 6 pk-ok 6
8751 * Variables for loop
8753 uchar *curr= (uchar*)buffer->buffer;
8754 uchar *end_of_buffer= (uchar*)buffer->buffer_end;
8755 NdbOperation::LockMode lm=
8756 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type);
8757 bool need_pk = (lm == NdbOperation::LM_Read);
8758 const NDBTAB *tab= m_table;
8759 const NDBINDEX *unique_idx= m_index[active_index].unique_index;
8760 const NDBINDEX *idx= m_index[active_index].index;
8761 const NdbOperation* lastOp= m_active_trans->getLastDefinedOperation();
8762 NdbIndexScanOperation* scanOp= 0;
8763 for (; multi_range_curr<multi_range_end && curr+reclength <= end_of_buffer;
8764 multi_range_curr++)
8766 part_id_range part_spec;
8767 if (m_use_partition_function)
8769 get_partition_set(table, curr, active_index,
8770 &multi_range_curr->start_key,
8771 &part_spec);
8772 DBUG_PRINT("info", ("part_spec.start_part: %u part_spec.end_part: %u",
8773 part_spec.start_part, part_spec.end_part));
8775 If partition pruning has found no partition in set
8776 we can skip this scan
8778 if (part_spec.start_part > part_spec.end_part)
8781 We can skip this partition since the key won't fit into any
8782 partition
8784 curr += reclength;
8785 multi_range_curr->range_flag |= SKIP_RANGE;
8786 continue;
8789 switch (cur_index_type) {
8790 case PRIMARY_KEY_ORDERED_INDEX:
8791 if (!(multi_range_curr->start_key.length == key_info->key_length &&
8792 multi_range_curr->start_key.flag == HA_READ_KEY_EXACT))
8793 goto range;
8794 // else fall through
8795 case PRIMARY_KEY_INDEX:
8797 multi_range_curr->range_flag |= UNIQUE_RANGE;
8798 if ((op= m_active_trans->getNdbOperation(tab)) &&
8799 !op->readTuple(lm) &&
8800 !set_primary_key(op, multi_range_curr->start_key.key) &&
8801 !define_read_attrs(curr, op) &&
8802 (!m_use_partition_function ||
8803 (op->setPartitionId(part_spec.start_part), TRUE)))
8804 curr += reclength;
8805 else
8806 ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
8807 break;
8809 break;
8810 case UNIQUE_ORDERED_INDEX:
8811 if (!(multi_range_curr->start_key.length == key_info->key_length &&
8812 multi_range_curr->start_key.flag == HA_READ_KEY_EXACT &&
8813 !check_null_in_key(key_info, multi_range_curr->start_key.key,
8814 multi_range_curr->start_key.length)))
8815 goto range;
8816 // else fall through
8817 case UNIQUE_INDEX:
8819 multi_range_curr->range_flag |= UNIQUE_RANGE;
8820 if ((op= m_active_trans->getNdbIndexOperation(unique_idx, tab)) &&
8821 !op->readTuple(lm) &&
8822 !set_index_key(op, key_info, multi_range_curr->start_key.key) &&
8823 !define_read_attrs(curr, op))
8824 curr += reclength;
8825 else
8826 ERR_RETURN(op ? op->getNdbError() : m_active_trans->getNdbError());
8827 break;
8829 case ORDERED_INDEX: {
8830 range:
8831 multi_range_curr->range_flag &= ~(uint)UNIQUE_RANGE;
8832 if (scanOp == 0)
8834 if (m_multi_cursor)
8836 scanOp= m_multi_cursor;
8837 DBUG_ASSERT(scanOp->getSorted() == sorted);
8838 DBUG_ASSERT(scanOp->getLockMode() ==
8839 (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type));
8840 if (scanOp->reset_bounds(m_force_send))
8841 DBUG_RETURN(ndb_err(m_active_trans));
8843 end_of_buffer -= reclength;
8845 else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab))
8846 &&!scanOp->readTuples(lm, 0, parallelism, sorted,
8847 FALSE, TRUE, need_pk, TRUE)
8848 &&!(m_cond && m_cond->generate_scan_filter(scanOp))
8849 &&!define_read_attrs(end_of_buffer-reclength, scanOp))
8851 m_multi_cursor= scanOp;
8852 m_multi_range_cursor_result_ptr= end_of_buffer-reclength;
8854 else
8856 ERR_RETURN(scanOp ? scanOp->getNdbError() :
8857 m_active_trans->getNdbError());
8861 const key_range *keys[2]= { &multi_range_curr->start_key,
8862 &multi_range_curr->end_key };
8863 if ((res= set_bounds(scanOp, active_index, FALSE, keys,
8864 multi_range_curr-ranges)))
8865 DBUG_RETURN(res);
8866 break;
8868 case UNDEFINED_INDEX:
8869 DBUG_ASSERT(FALSE);
8870 DBUG_RETURN(1);
8871 break;
8875 if (multi_range_curr != multi_range_end)
8878 * Mark that we're using entire buffer (even if might not) as
8879 * we haven't read all ranges for some reason
8880 * This as we don't want mysqld to reuse the buffer when we read
8881 * the remaining ranges
8883 buffer->end_of_used_area= (uchar*)buffer->buffer_end;
8885 else
8887 buffer->end_of_used_area= curr;
8891 * Set first operation in multi range
8893 m_current_multi_operation=
8894 lastOp ? lastOp->next() : m_active_trans->getFirstDefinedOperation();
8895 if (!(res= execute_no_commit_ie(this, m_active_trans,true)))
8897 m_multi_range_defined= multi_range_curr;
8898 multi_range_curr= ranges;
8899 m_multi_range_result_ptr= (uchar*)buffer->buffer;
8900 DBUG_RETURN(read_multi_range_next(found_range_p));
8902 ERR_RETURN(m_active_trans->getNdbError());
8905 #if 0
8906 #define DBUG_MULTI_RANGE(x) DBUG_PRINT("info", ("read_multi_range_next: case %d\n", x));
8907 #else
8908 #define DBUG_MULTI_RANGE(x)
8909 #endif
8912 ha_ndbcluster::read_multi_range_next(KEY_MULTI_RANGE ** multi_range_found_p)
8914 DBUG_ENTER("ha_ndbcluster::read_multi_range_next");
8915 if (m_disable_multi_read)
8917 DBUG_MULTI_RANGE(11);
8918 DBUG_RETURN(handler::read_multi_range_next(multi_range_found_p));
8921 int res;
8922 int range_no;
8923 ulong reclength= table_share->reclength;
8924 const NdbOperation* op= m_current_multi_operation;
8925 for (;multi_range_curr < m_multi_range_defined; multi_range_curr++)
8927 DBUG_MULTI_RANGE(12);
8928 if (multi_range_curr->range_flag & SKIP_RANGE)
8929 continue;
8930 if (multi_range_curr->range_flag & UNIQUE_RANGE)
8932 if (op->getNdbError().code == 0)
8934 DBUG_MULTI_RANGE(13);
8935 goto found_next;
8938 op= m_active_trans->getNextCompletedOperation(op);
8939 m_multi_range_result_ptr += reclength;
8940 continue;
8942 else if (m_multi_cursor && !multi_range_sorted)
8944 DBUG_MULTI_RANGE(1);
8945 if ((res= fetch_next(m_multi_cursor)) == 0)
8947 DBUG_MULTI_RANGE(2);
8948 range_no= m_multi_cursor->get_range_no();
8949 goto found;
8951 else
8953 DBUG_MULTI_RANGE(14);
8954 goto close_scan;
8957 else if (m_multi_cursor && multi_range_sorted)
8959 if (m_active_cursor && (res= fetch_next(m_multi_cursor)))
8961 DBUG_MULTI_RANGE(3);
8962 goto close_scan;
8965 range_no= m_multi_cursor->get_range_no();
8966 uint current_range_no= multi_range_curr - m_multi_ranges;
8967 if ((uint) range_no == current_range_no)
8969 DBUG_MULTI_RANGE(4);
8970 // return current row
8971 goto found;
8973 else if (range_no > (int)current_range_no)
8975 DBUG_MULTI_RANGE(5);
8976 // wait with current row
8977 m_active_cursor= 0;
8978 continue;
8980 else
8982 DBUG_MULTI_RANGE(6);
8983 // First fetch from cursor
8984 DBUG_ASSERT(range_no == -1);
8985 if ((res= m_multi_cursor->nextResult(TRUE)))
8987 DBUG_MULTI_RANGE(15);
8988 goto close_scan;
8990 multi_range_curr--; // Will be increased in for-loop
8991 continue;
8994 else /* m_multi_cursor == 0 */
8996 DBUG_MULTI_RANGE(7);
8998 * Corresponds to range 5 in example in read_multi_range_first
9000 (void)1;
9001 continue;
9004 DBUG_ASSERT(FALSE); // Should only get here via goto's
9005 close_scan:
9006 if (res == 1)
9008 m_multi_cursor->close(FALSE, TRUE);
9009 m_active_cursor= m_multi_cursor= 0;
9010 DBUG_MULTI_RANGE(8);
9011 continue;
9013 else
9015 DBUG_MULTI_RANGE(9);
9016 DBUG_RETURN(ndb_err(m_active_trans));
9020 if (multi_range_curr == multi_range_end)
9022 DBUG_MULTI_RANGE(16);
9023 Thd_ndb *thd_ndb= get_thd_ndb(current_thd);
9024 thd_ndb->query_state&= NDB_QUERY_NORMAL;
9025 DBUG_RETURN(HA_ERR_END_OF_FILE);
9029 * Read remaining ranges
9031 DBUG_RETURN(read_multi_range_first(multi_range_found_p,
9032 multi_range_curr,
9033 multi_range_end - multi_range_curr,
9034 multi_range_sorted,
9035 multi_range_buffer));
9037 found:
9039 * Found a record belonging to a scan
9041 m_active_cursor= m_multi_cursor;
9042 * multi_range_found_p= m_multi_ranges + range_no;
9043 memcpy(table->record[0], m_multi_range_cursor_result_ptr, reclength);
9044 setup_recattr(m_active_cursor->getFirstRecAttr());
9045 unpack_record(table->record[0]);
9046 table->status= 0;
9047 DBUG_RETURN(0);
9049 found_next:
9051 * Found a record belonging to a pk/index op,
9052 * copy result and move to next to prepare for next call
9054 * multi_range_found_p= multi_range_curr;
9055 memcpy(table->record[0], m_multi_range_result_ptr, reclength);
9056 setup_recattr(op->getFirstRecAttr());
9057 unpack_record(table->record[0]);
9058 table->status= 0;
9060 multi_range_curr++;
9061 m_current_multi_operation= m_active_trans->getNextCompletedOperation(op);
9062 m_multi_range_result_ptr += reclength;
9063 DBUG_RETURN(0);
9067 ha_ndbcluster::setup_recattr(const NdbRecAttr* curr)
9069 DBUG_ENTER("setup_recattr");
9071 Field **field, **end;
9072 NdbValue *value= m_value;
9074 end= table->field + table_share->fields;
9076 for (field= table->field; field < end; field++, value++)
9078 if ((* value).ptr)
9080 DBUG_ASSERT(curr != 0);
9081 NdbValue* val= m_value + curr->getColumn()->getColumnNo();
9082 DBUG_ASSERT(val->ptr);
9083 val->rec= curr;
9084 curr= curr->next();
9088 DBUG_RETURN(0);
9092 @param[in] comment table comment defined by user
9094 @return
9095 table comment + additional
9097 char*
9098 ha_ndbcluster::update_table_comment(
9099 /* out: table comment + additional */
9100 const char* comment)/* in: table comment defined by user */
9102 uint length= strlen(comment);
9103 if (length > 64000 - 3)
9105 return((char*)comment); /* string too long */
9108 Ndb* ndb;
9109 if (!(ndb= get_ndb()))
9111 return((char*)comment);
9114 if (ndb->setDatabaseName(m_dbname))
9116 return((char*)comment);
9118 const NDBTAB* tab= m_table;
9119 DBUG_ASSERT(tab != NULL);
9121 char *str;
9122 const char *fmt="%s%snumber_of_replicas: %d";
9123 const unsigned fmt_len_plus_extra= length + strlen(fmt);
9124 if ((str= (char*) my_malloc(fmt_len_plus_extra, MYF(0))) == NULL)
9126 sql_print_error("ha_ndbcluster::update_table_comment: "
9127 "my_malloc(%u) failed", (unsigned int)fmt_len_plus_extra);
9128 return (char*)comment;
9131 my_snprintf(str,fmt_len_plus_extra,fmt,comment,
9132 length > 0 ? " ":"",
9133 tab->getReplicaCount());
9134 return str;
9139 Utility thread main loop.
9141 pthread_handler_t ndb_util_thread_func(void *arg __attribute__((unused)))
9143 THD *thd; /* needs to be first for thread_stack */
9144 struct timespec abstime;
9145 Thd_ndb *thd_ndb;
9146 uint share_list_size= 0;
9147 NDB_SHARE **share_list= NULL;
9149 my_thread_init();
9150 DBUG_ENTER("ndb_util_thread");
9151 DBUG_PRINT("enter", ("ndb_cache_check_time: %lu", ndb_cache_check_time));
9153 pthread_mutex_lock(&LOCK_ndb_util_thread);
9155 thd= new THD; /* note that contructor of THD uses DBUG_ */
9156 if (thd == NULL)
9158 my_errno= HA_ERR_OUT_OF_MEM;
9159 DBUG_RETURN(NULL);
9161 THD_CHECK_SENTRY(thd);
9162 pthread_detach_this_thread();
9163 ndb_util_thread= pthread_self();
9165 thd->thread_stack= (char*)&thd; /* remember where our stack is */
9166 if (thd->store_globals())
9167 goto ndb_util_thread_fail;
9168 lex_start(thd);
9169 thd->init_for_queries();
9170 thd->version=refresh_version;
9171 thd->main_security_ctx.host_or_ip= "";
9172 thd->client_capabilities = 0;
9173 my_net_init(&thd->net, 0);
9174 thd->main_security_ctx.master_access= ~0;
9175 thd->main_security_ctx.priv_user = 0;
9177 CHARSET_INFO *charset_connection;
9178 charset_connection= get_charset_by_csname("utf8",
9179 MY_CS_PRIMARY, MYF(MY_WME));
9180 thd->variables.character_set_client= charset_connection;
9181 thd->variables.character_set_results= charset_connection;
9182 thd->variables.collation_connection= charset_connection;
9183 thd->update_charset();
9185 /* Signal successful initialization */
9186 ndb_util_thread_running= 1;
9187 pthread_cond_signal(&COND_ndb_util_ready);
9188 pthread_mutex_unlock(&LOCK_ndb_util_thread);
9191 wait for mysql server to start
9193 pthread_mutex_lock(&LOCK_server_started);
9194 while (!mysqld_server_started)
9196 set_timespec(abstime, 1);
9197 pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
9198 &abstime);
9199 if (ndbcluster_terminating)
9201 pthread_mutex_unlock(&LOCK_server_started);
9202 pthread_mutex_lock(&LOCK_ndb_util_thread);
9203 goto ndb_util_thread_end;
9206 pthread_mutex_unlock(&LOCK_server_started);
9209 Wait for cluster to start
9211 pthread_mutex_lock(&LOCK_ndb_util_thread);
9212 while (!ndb_cluster_node_id && (ndbcluster_hton->slot != ~(uint)0))
9214 /* ndb not connected yet */
9215 pthread_cond_wait(&COND_ndb_util_thread, &LOCK_ndb_util_thread);
9216 if (ndbcluster_terminating)
9217 goto ndb_util_thread_end;
9219 pthread_mutex_unlock(&LOCK_ndb_util_thread);
9221 /* Get thd_ndb for this thread */
9222 if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
9224 sql_print_error("Could not allocate Thd_ndb object");
9225 pthread_mutex_lock(&LOCK_ndb_util_thread);
9226 goto ndb_util_thread_end;
9228 set_thd_ndb(thd, thd_ndb);
9229 thd_ndb->options|= TNO_NO_LOG_SCHEMA_OP;
9231 #ifdef HAVE_NDB_BINLOG
9232 if (ndb_extra_logging && ndb_binlog_running)
9233 sql_print_information("NDB Binlog: Ndb tables initially read only.");
9234 /* create tables needed by the replication */
9235 ndbcluster_setup_binlog_table_shares(thd);
9236 #else
9238 Get all table definitions from the storage node
9240 ndbcluster_find_all_files(thd);
9241 #endif
9243 set_timespec(abstime, 0);
9244 for (;;)
9246 pthread_mutex_lock(&LOCK_ndb_util_thread);
9247 if (!ndbcluster_terminating)
9248 pthread_cond_timedwait(&COND_ndb_util_thread,
9249 &LOCK_ndb_util_thread,
9250 &abstime);
9251 if (ndbcluster_terminating) /* Shutting down server */
9252 goto ndb_util_thread_end;
9253 pthread_mutex_unlock(&LOCK_ndb_util_thread);
9254 #ifdef NDB_EXTRA_DEBUG_UTIL_THREAD
9255 DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %lu",
9256 ndb_cache_check_time));
9257 #endif
9259 #ifdef HAVE_NDB_BINLOG
9261 Check that the ndb_apply_status_share and ndb_schema_share
9262 have been created.
9263 If not try to create it
9265 if (!ndb_binlog_tables_inited)
9266 ndbcluster_setup_binlog_table_shares(thd);
9267 #endif
9269 if (ndb_cache_check_time == 0)
9271 /* Wake up in 1 second to check if value has changed */
9272 set_timespec(abstime, 1);
9273 continue;
9276 /* Lock mutex and fill list with pointers to all open tables */
9277 NDB_SHARE *share;
9278 pthread_mutex_lock(&ndbcluster_mutex);
9279 uint i, open_count, record_count= ndbcluster_open_tables.records;
9280 if (share_list_size < record_count)
9282 NDB_SHARE ** new_share_list= new NDB_SHARE * [record_count];
9283 if (!new_share_list)
9285 sql_print_warning("ndb util thread: malloc failure, "
9286 "query cache not maintained properly");
9287 pthread_mutex_unlock(&ndbcluster_mutex);
9288 goto next; // At least do not crash
9290 delete [] share_list;
9291 share_list_size= record_count;
9292 share_list= new_share_list;
9294 for (i= 0, open_count= 0; i < record_count; i++)
9296 share= (NDB_SHARE *)hash_element(&ndbcluster_open_tables, i);
9297 #ifdef HAVE_NDB_BINLOG
9298 if ((share->use_count - (int) (share->op != 0) - (int) (share->op != 0))
9299 <= 0)
9300 continue; // injector thread is the only user, skip statistics
9301 share->util_lock= current_thd; // Mark that util thread has lock
9302 #endif /* HAVE_NDB_BINLOG */
9303 /* ndb_share reference temporary, free below */
9304 share->use_count++; /* Make sure the table can't be closed */
9305 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
9306 share->key, share->use_count));
9307 DBUG_PRINT("ndb_util_thread",
9308 ("Found open table[%d]: %s, use_count: %d",
9309 i, share->table_name, share->use_count));
9311 /* Store pointer to table */
9312 share_list[open_count++]= share;
9314 pthread_mutex_unlock(&ndbcluster_mutex);
9316 /* Iterate through the open files list */
9317 for (i= 0; i < open_count; i++)
9319 share= share_list[i];
9320 #ifdef HAVE_NDB_BINLOG
9321 if ((share->use_count - (int) (share->op != 0) - (int) (share->op != 0))
9322 <= 1)
9325 Util thread and injector thread is the only user, skip statistics
9327 /* ndb_share reference temporary free */
9328 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
9329 share->key, share->use_count));
9330 free_share(&share);
9331 continue;
9333 #endif /* HAVE_NDB_BINLOG */
9334 DBUG_PRINT("ndb_util_thread",
9335 ("Fetching commit count for: %s", share->key));
9337 struct Ndb_statistics stat;
9338 uint lock;
9339 pthread_mutex_lock(&share->mutex);
9340 lock= share->commit_count_lock;
9341 pthread_mutex_unlock(&share->mutex);
9343 /* Contact NDB to get commit count for table */
9344 Ndb* ndb= thd_ndb->ndb;
9345 if (ndb->setDatabaseName(share->db))
9347 goto loop_next;
9349 Ndb_table_guard ndbtab_g(ndb->getDictionary(), share->table_name);
9350 if (ndbtab_g.get_table() &&
9351 ndb_get_table_statistics(NULL, FALSE, ndb,
9352 ndbtab_g.get_table(), &stat) == 0)
9354 #ifndef DBUG_OFF
9355 char buff[22], buff2[22];
9356 #endif
9357 DBUG_PRINT("info",
9358 ("Table: %s commit_count: %s rows: %s",
9359 share->key,
9360 llstr(stat.commit_count, buff),
9361 llstr(stat.row_count, buff2)));
9363 else
9365 DBUG_PRINT("ndb_util_thread",
9366 ("Error: Could not get commit count for table %s",
9367 share->key));
9368 stat.commit_count= 0;
9371 loop_next:
9372 pthread_mutex_lock(&share->mutex);
9373 if (share->commit_count_lock == lock)
9374 share->commit_count= stat.commit_count;
9375 pthread_mutex_unlock(&share->mutex);
9377 /* ndb_share reference temporary free */
9378 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
9379 share->key, share->use_count));
9380 free_share(&share);
9382 next:
9383 /* Calculate new time to wake up */
9384 int secs= 0;
9385 int msecs= ndb_cache_check_time;
9387 struct timeval tick_time;
9388 gettimeofday(&tick_time, 0);
9389 abstime.tv_sec= tick_time.tv_sec;
9390 abstime.tv_nsec= tick_time.tv_usec * 1000;
9392 if (msecs >= 1000){
9393 secs= msecs / 1000;
9394 msecs= msecs % 1000;
9397 abstime.tv_sec+= secs;
9398 abstime.tv_nsec+= msecs * 1000000;
9399 if (abstime.tv_nsec >= 1000000000) {
9400 abstime.tv_sec+= 1;
9401 abstime.tv_nsec-= 1000000000;
9405 pthread_mutex_lock(&LOCK_ndb_util_thread);
9407 ndb_util_thread_end:
9408 net_end(&thd->net);
9409 ndb_util_thread_fail:
9410 if (share_list)
9411 delete [] share_list;
9412 thd->cleanup();
9413 delete thd;
9415 /* signal termination */
9416 ndb_util_thread_running= 0;
9417 pthread_cond_signal(&COND_ndb_util_ready);
9418 pthread_mutex_unlock(&LOCK_ndb_util_thread);
9419 DBUG_PRINT("exit", ("ndb_util_thread"));
9421 DBUG_LEAVE; // Must match DBUG_ENTER()
9422 my_thread_end();
9423 pthread_exit(0);
9424 return NULL; // Avoid compiler warnings
9428 Condition pushdown
9431 Push a condition to ndbcluster storage engine for evaluation
9432 during table and index scans. The conditions will be stored on a stack
9433 for possibly storing several conditions. The stack can be popped
9434 by calling cond_pop, handler::extra(HA_EXTRA_RESET) (handler::reset())
9435 will clear the stack.
9436 The current implementation supports arbitrary AND/OR nested conditions
9437 with comparisons between columns and constants (including constant
9438 expressions and function calls) and the following comparison operators:
9439 =, !=, >, >=, <, <=, "is null", and "is not null".
9441 @retval
9442 NULL The condition was supported and will be evaluated for each
9443 row found during the scan
9444 @retval
9445 cond The condition was not supported and all rows will be returned from
9446 the scan for evaluation (and thus not saved on stack)
9448 const
9449 COND*
9450 ha_ndbcluster::cond_push(const COND *cond)
9452 DBUG_ENTER("cond_push");
9453 if (!m_cond)
9454 m_cond= new ha_ndbcluster_cond;
9455 if (!m_cond)
9457 my_errno= HA_ERR_OUT_OF_MEM;
9458 DBUG_RETURN(NULL);
9460 DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname, QT_ORDINARY););
9461 DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table));
9465 Pop the top condition from the condition stack of the handler instance.
9467 void
9468 ha_ndbcluster::cond_pop()
9470 if (m_cond)
9471 m_cond->cond_pop();
9476 get table space info for SHOW CREATE TABLE
9478 char* ha_ndbcluster::get_tablespace_name(THD *thd, char* name, uint name_len)
9480 Ndb *ndb= check_ndb_in_thd(thd);
9481 NDBDICT *ndbdict= ndb->getDictionary();
9482 NdbError ndberr;
9483 Uint32 id;
9484 ndb->setDatabaseName(m_dbname);
9485 const NDBTAB *ndbtab= m_table;
9486 DBUG_ASSERT(ndbtab != NULL);
9487 if (!ndbtab->getTablespace(&id))
9489 return 0;
9492 NdbDictionary::Tablespace ts= ndbdict->getTablespace(id);
9493 ndberr= ndbdict->getNdbError();
9494 if(ndberr.classification != NdbError::NoError)
9495 goto err;
9496 DBUG_PRINT("info", ("Found tablespace '%s'", ts.getName()));
9497 if (name)
9499 strxnmov(name, name_len, ts.getName(), NullS);
9500 return name;
9502 else
9503 return (my_strdup(ts.getName(), MYF(0)));
9505 err:
9506 if (ndberr.status == NdbError::TemporaryError)
9507 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
9508 ER_GET_TEMPORARY_ERRMSG, ER(ER_GET_TEMPORARY_ERRMSG),
9509 ndberr.code, ndberr.message, "NDB");
9510 else
9511 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
9512 ER_GET_ERRMSG, ER(ER_GET_ERRMSG),
9513 ndberr.code, ndberr.message, "NDB");
9514 return 0;
9518 Implements the SHOW NDB STATUS command.
9520 bool
9521 ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print,
9522 enum ha_stat_type stat_type)
9524 char buf[IO_SIZE];
9525 uint buflen;
9526 DBUG_ENTER("ndbcluster_show_status");
9528 if (stat_type != HA_ENGINE_STATUS)
9530 DBUG_RETURN(FALSE);
9533 update_status_variables(g_ndb_cluster_connection);
9534 buflen=
9535 my_snprintf(buf, sizeof(buf),
9536 "cluster_node_id=%ld, "
9537 "connected_host=%s, "
9538 "connected_port=%ld, "
9539 "number_of_data_nodes=%ld, "
9540 "number_of_ready_data_nodes=%ld, "
9541 "connect_count=%ld",
9542 ndb_cluster_node_id,
9543 ndb_connected_host,
9544 ndb_connected_port,
9545 ndb_number_of_data_nodes,
9546 ndb_number_of_ready_data_nodes,
9547 ndb_connect_count);
9548 if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
9549 STRING_WITH_LEN("connection"), buf, buflen))
9550 DBUG_RETURN(TRUE);
9552 if (get_thd_ndb(thd) && get_thd_ndb(thd)->ndb)
9554 Ndb* ndb= (get_thd_ndb(thd))->ndb;
9555 Ndb::Free_list_usage tmp;
9556 tmp.m_name= 0;
9557 while (ndb->get_free_list_usage(&tmp))
9559 buflen=
9560 my_snprintf(buf, sizeof(buf),
9561 "created=%u, free=%u, sizeof=%u",
9562 tmp.m_created, tmp.m_free, tmp.m_sizeof);
9563 if (stat_print(thd, ndbcluster_hton_name, ndbcluster_hton_name_length,
9564 tmp.m_name, strlen(tmp.m_name), buf, buflen))
9565 DBUG_RETURN(TRUE);
9568 #ifdef HAVE_NDB_BINLOG
9569 ndbcluster_show_status_binlog(thd, stat_print, stat_type);
9570 #endif
9572 DBUG_RETURN(FALSE);
9577 Create a table in NDB Cluster
9579 static uint get_no_fragments(ulonglong max_rows)
9581 #if MYSQL_VERSION_ID >= 50000
9582 uint acc_row_size= 25 + /*safety margin*/ 2;
9583 #else
9584 uint acc_row_size= pk_length*4;
9585 /* add acc overhead */
9586 if (pk_length <= 8) /* main page will set the limit */
9587 acc_row_size+= 25 + /*safety margin*/ 2;
9588 else /* overflow page will set the limit */
9589 acc_row_size+= 4 + /*safety margin*/ 4;
9590 #endif
9591 ulonglong acc_fragment_size= 512*1024*1024;
9592 #if MYSQL_VERSION_ID >= 50100
9593 return (max_rows*acc_row_size)/acc_fragment_size+1;
9594 #else
9595 return ((max_rows*acc_row_size)/acc_fragment_size+1
9596 +1/*correct rounding*/)/2;
9597 #endif
9602 Routine to adjust default number of partitions to always be a multiple
9603 of number of nodes and never more than 4 times the number of nodes.
9606 static bool adjusted_frag_count(uint no_fragments, uint no_nodes,
9607 uint &reported_frags)
9609 uint i= 0;
9610 reported_frags= no_nodes;
9611 while (reported_frags < no_fragments && ++i < 4 &&
9612 (reported_frags + no_nodes) < MAX_PARTITIONS)
9613 reported_frags+= no_nodes;
9614 return (reported_frags < no_fragments);
9617 int ha_ndbcluster::get_default_no_partitions(HA_CREATE_INFO *create_info)
9619 ha_rows max_rows, min_rows;
9620 if (create_info)
9622 max_rows= create_info->max_rows;
9623 min_rows= create_info->min_rows;
9625 else
9627 max_rows= table_share->max_rows;
9628 min_rows= table_share->min_rows;
9630 uint reported_frags;
9631 uint no_fragments=
9632 get_no_fragments(max_rows >= min_rows ? max_rows : min_rows);
9633 uint no_nodes= g_ndb_cluster_connection->no_db_nodes();
9634 if (adjusted_frag_count(no_fragments, no_nodes, reported_frags))
9636 push_warning(current_thd,
9637 MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
9638 "Ndb might have problems storing the max amount of rows specified");
9640 return (int)reported_frags;
9645 Set-up auto-partitioning for NDB Cluster
9647 SYNOPSIS
9648 set_auto_partitions()
9649 part_info Partition info struct to set-up
9651 RETURN VALUE
9652 NONE
9654 DESCRIPTION
9655 Set-up auto partitioning scheme for tables that didn't define any
9656 partitioning. We'll use PARTITION BY KEY() in this case which
9657 translates into partition by primary key if a primary key exists
9658 and partition by hidden key otherwise.
9661 void ha_ndbcluster::set_auto_partitions(partition_info *part_info)
9663 DBUG_ENTER("ha_ndbcluster::set_auto_partitions");
9664 part_info->list_of_part_fields= TRUE;
9665 part_info->part_type= HASH_PARTITION;
9666 switch (opt_ndb_distribution_id)
9668 case ND_KEYHASH:
9669 part_info->linear_hash_ind= FALSE;
9670 break;
9671 case ND_LINHASH:
9672 part_info->linear_hash_ind= TRUE;
9673 break;
9675 DBUG_VOID_RETURN;
9679 int ha_ndbcluster::set_range_data(void *tab_ref, partition_info *part_info)
9681 NDBTAB *tab= (NDBTAB*)tab_ref;
9682 int32 *range_data= (int32*)my_malloc(part_info->no_parts*sizeof(int32),
9683 MYF(0));
9684 uint i;
9685 int error= 0;
9686 bool unsigned_flag= part_info->part_expr->unsigned_flag;
9687 DBUG_ENTER("set_range_data");
9689 if (!range_data)
9691 mem_alloc_error(part_info->no_parts*sizeof(int32));
9692 DBUG_RETURN(1);
9694 for (i= 0; i < part_info->no_parts; i++)
9696 longlong range_val= part_info->range_int_array[i];
9697 if (unsigned_flag)
9698 range_val-= 0x8000000000000000ULL;
9699 if (range_val < INT_MIN32 || range_val >= INT_MAX32)
9701 if ((i != part_info->no_parts - 1) ||
9702 (range_val != LONGLONG_MAX))
9704 my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB");
9705 error= 1;
9706 goto error;
9708 range_val= INT_MAX32;
9710 range_data[i]= (int32)range_val;
9712 tab->setRangeListData(range_data, sizeof(int32)*part_info->no_parts);
9713 error:
9714 my_free((char*)range_data, MYF(0));
9715 DBUG_RETURN(error);
9718 int ha_ndbcluster::set_list_data(void *tab_ref, partition_info *part_info)
9720 NDBTAB *tab= (NDBTAB*)tab_ref;
9721 int32 *list_data= (int32*)my_malloc(part_info->no_list_values * 2
9722 * sizeof(int32), MYF(0));
9723 uint32 *part_id, i;
9724 int error= 0;
9725 bool unsigned_flag= part_info->part_expr->unsigned_flag;
9726 DBUG_ENTER("set_list_data");
9728 if (!list_data)
9730 mem_alloc_error(part_info->no_list_values*2*sizeof(int32));
9731 DBUG_RETURN(1);
9733 for (i= 0; i < part_info->no_list_values; i++)
9735 LIST_PART_ENTRY *list_entry= &part_info->list_array[i];
9736 longlong list_val= list_entry->list_value;
9737 if (unsigned_flag)
9738 list_val-= 0x8000000000000000ULL;
9739 if (list_val < INT_MIN32 || list_val > INT_MAX32)
9741 my_error(ER_LIMITED_PART_RANGE, MYF(0), "NDB");
9742 error= 1;
9743 goto error;
9745 list_data[2*i]= (int32)list_val;
9746 part_id= (uint32*)&list_data[2*i+1];
9747 *part_id= list_entry->partition_id;
9749 tab->setRangeListData(list_data, 2*sizeof(int32)*part_info->no_list_values);
9750 error:
9751 my_free((char*)list_data, MYF(0));
9752 DBUG_RETURN(error);
9756 User defined partitioning set-up. We need to check how many fragments the
9757 user wants defined and which node groups to put those into. Later we also
9758 want to attach those partitions to a tablespace.
9760 All the functionality of the partition function, partition limits and so
9761 forth are entirely handled by the MySQL Server. There is one exception to
9762 this rule for PARTITION BY KEY where NDB handles the hash function and
9763 this type can thus be handled transparently also by NDB API program.
9764 For RANGE, HASH and LIST and subpartitioning the NDB API programs must
9765 implement the function to map to a partition.
9768 uint ha_ndbcluster::set_up_partition_info(partition_info *part_info,
9769 TABLE *table,
9770 void *tab_par)
9772 uint16 frag_data[MAX_PARTITIONS];
9773 char *ts_names[MAX_PARTITIONS];
9774 ulong fd_index= 0, i, j;
9775 NDBTAB *tab= (NDBTAB*)tab_par;
9776 NDBTAB::FragmentType ftype= NDBTAB::UserDefined;
9777 partition_element *part_elem;
9778 bool first= TRUE;
9779 uint tot_ts_name_len;
9780 List_iterator<partition_element> part_it(part_info->partitions);
9781 int error;
9782 DBUG_ENTER("ha_ndbcluster::set_up_partition_info");
9784 if (part_info->part_type == HASH_PARTITION &&
9785 part_info->list_of_part_fields == TRUE)
9787 Field **fields= part_info->part_field_array;
9789 if (part_info->linear_hash_ind)
9790 ftype= NDBTAB::DistrKeyLin;
9791 else
9792 ftype= NDBTAB::DistrKeyHash;
9794 for (i= 0; i < part_info->part_field_list.elements; i++)
9796 NDBCOL *col= tab->getColumn(fields[i]->field_index);
9797 DBUG_PRINT("info",("setting dist key on %s", col->getName()));
9798 col->setPartitionKey(TRUE);
9801 else
9803 if (!current_thd->variables.new_mode)
9805 push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
9806 ER_ILLEGAL_HA_CREATE_OPTION,
9807 ER(ER_ILLEGAL_HA_CREATE_OPTION),
9808 ndbcluster_hton_name,
9809 "LIST, RANGE and HASH partition disabled by default,"
9810 " use --new option to enable");
9811 DBUG_RETURN(HA_ERR_UNSUPPORTED);
9814 Create a shadow field for those tables that have user defined
9815 partitioning. This field stores the value of the partition
9816 function such that NDB can handle reorganisations of the data
9817 even when the MySQL Server isn't available to assist with
9818 calculation of the partition function value.
9820 NDBCOL col;
9821 DBUG_PRINT("info", ("Generating partition func value field"));
9822 col.setName("$PART_FUNC_VALUE");
9823 col.setType(NdbDictionary::Column::Int);
9824 col.setLength(1);
9825 col.setNullable(FALSE);
9826 col.setPrimaryKey(FALSE);
9827 col.setAutoIncrement(FALSE);
9828 tab->addColumn(col);
9829 if (part_info->part_type == RANGE_PARTITION)
9831 if ((error= set_range_data((void*)tab, part_info)))
9833 DBUG_RETURN(error);
9836 else if (part_info->part_type == LIST_PARTITION)
9838 if ((error= set_list_data((void*)tab, part_info)))
9840 DBUG_RETURN(error);
9844 tab->setFragmentType(ftype);
9845 i= 0;
9846 tot_ts_name_len= 0;
9849 uint ng;
9850 part_elem= part_it++;
9851 if (!part_info->is_sub_partitioned())
9853 ng= part_elem->nodegroup_id;
9854 if (first && ng == UNDEF_NODEGROUP)
9855 ng= 0;
9856 ts_names[fd_index]= part_elem->tablespace_name;
9857 frag_data[fd_index++]= ng;
9859 else
9861 List_iterator<partition_element> sub_it(part_elem->subpartitions);
9862 j= 0;
9865 part_elem= sub_it++;
9866 ng= part_elem->nodegroup_id;
9867 if (first && ng == UNDEF_NODEGROUP)
9868 ng= 0;
9869 ts_names[fd_index]= part_elem->tablespace_name;
9870 frag_data[fd_index++]= ng;
9871 } while (++j < part_info->no_subparts);
9873 first= FALSE;
9874 } while (++i < part_info->no_parts);
9875 tab->setDefaultNoPartitionsFlag(part_info->use_default_no_partitions);
9876 tab->setLinearFlag(part_info->linear_hash_ind);
9878 ha_rows max_rows= table_share->max_rows;
9879 ha_rows min_rows= table_share->min_rows;
9880 if (max_rows < min_rows)
9881 max_rows= min_rows;
9882 if (max_rows != (ha_rows)0) /* default setting, don't set fragmentation */
9884 tab->setMaxRows(max_rows);
9885 tab->setMinRows(min_rows);
9888 tab->setTablespaceNames(ts_names, fd_index*sizeof(char*));
9889 tab->setFragmentCount(fd_index);
9890 tab->setFragmentData(&frag_data, fd_index*2);
9891 DBUG_RETURN(0);
9895 bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info,
9896 uint table_changes)
9898 DBUG_ENTER("ha_ndbcluster::check_if_incompatible_data");
9899 uint i;
9900 const NDBTAB *tab= (const NDBTAB *) m_table;
9902 if (current_thd->variables.ndb_use_copying_alter_table)
9904 DBUG_PRINT("info", ("On-line alter table disabled"));
9905 DBUG_RETURN(COMPATIBLE_DATA_NO);
9908 int pk= 0;
9909 int ai= 0;
9911 if (create_info->tablespace)
9912 create_info->storage_media = HA_SM_DISK;
9913 else
9914 create_info->storage_media = HA_SM_MEMORY;
9916 for (i= 0; i < table->s->fields; i++)
9918 Field *field= table->field[i];
9919 const NDBCOL *col= tab->getColumn(i);
9920 if ((col->getStorageType() == NDB_STORAGETYPE_MEMORY && create_info->storage_media != HA_SM_MEMORY) ||
9921 (col->getStorageType() == NDB_STORAGETYPE_DISK && create_info->storage_media != HA_SM_DISK))
9923 DBUG_PRINT("info", ("Column storage media is changed"));
9924 DBUG_RETURN(COMPATIBLE_DATA_NO);
9927 if (field->flags & FIELD_IS_RENAMED)
9929 DBUG_PRINT("info", ("Field has been renamed, copy table"));
9930 DBUG_RETURN(COMPATIBLE_DATA_NO);
9932 if ((field->flags & FIELD_IN_ADD_INDEX) &&
9933 col->getStorageType() == NdbDictionary::Column::StorageTypeDisk)
9935 DBUG_PRINT("info", ("add/drop index not supported for disk stored column"));
9936 DBUG_RETURN(COMPATIBLE_DATA_NO);
9939 if (field->flags & PRI_KEY_FLAG)
9940 pk=1;
9941 if (field->flags & FIELD_IN_ADD_INDEX)
9942 ai=1;
9945 char tablespace_name[FN_LEN + 1];
9946 if (get_tablespace_name(current_thd, tablespace_name, FN_LEN))
9948 if (create_info->tablespace)
9950 if (strcmp(create_info->tablespace, tablespace_name))
9952 DBUG_PRINT("info", ("storage media is changed, old tablespace=%s, new tablespace=%s",
9953 tablespace_name, create_info->tablespace));
9954 DBUG_RETURN(COMPATIBLE_DATA_NO);
9957 else
9959 DBUG_PRINT("info", ("storage media is changed, old is DISK and tablespace=%s, new is MEM",
9960 tablespace_name));
9961 DBUG_RETURN(COMPATIBLE_DATA_NO);
9964 else
9966 if (create_info->storage_media != HA_SM_MEMORY)
9968 DBUG_PRINT("info", ("storage media is changed, old is MEM, new is DISK and tablespace=%s",
9969 create_info->tablespace));
9970 DBUG_RETURN(COMPATIBLE_DATA_NO);
9974 if (table_changes != IS_EQUAL_YES)
9975 DBUG_RETURN(COMPATIBLE_DATA_NO);
9977 /* Check that auto_increment value was not changed */
9978 if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
9979 create_info->auto_increment_value != 0)
9981 DBUG_PRINT("info", ("auto_increment value changed"));
9982 DBUG_RETURN(COMPATIBLE_DATA_NO);
9985 /* Check that row format didn't change */
9986 if ((create_info->used_fields & HA_CREATE_USED_AUTO) &&
9987 get_row_type() != create_info->row_type)
9989 DBUG_PRINT("info", ("row format changed"));
9990 DBUG_RETURN(COMPATIBLE_DATA_NO);
9993 DBUG_PRINT("info", ("new table seems compatible"));
9994 DBUG_RETURN(COMPATIBLE_DATA_YES);
9997 bool set_up_tablespace(st_alter_tablespace *alter_info,
9998 NdbDictionary::Tablespace *ndb_ts)
10000 ndb_ts->setName(alter_info->tablespace_name);
10001 ndb_ts->setExtentSize(alter_info->extent_size);
10002 ndb_ts->setDefaultLogfileGroup(alter_info->logfile_group_name);
10003 return FALSE;
10006 bool set_up_datafile(st_alter_tablespace *alter_info,
10007 NdbDictionary::Datafile *ndb_df)
10009 if (alter_info->max_size > 0)
10011 my_error(ER_TABLESPACE_AUTO_EXTEND_ERROR, MYF(0));
10012 return TRUE;
10014 ndb_df->setPath(alter_info->data_file_name);
10015 ndb_df->setSize(alter_info->initial_size);
10016 ndb_df->setTablespace(alter_info->tablespace_name);
10017 return FALSE;
10020 bool set_up_logfile_group(st_alter_tablespace *alter_info,
10021 NdbDictionary::LogfileGroup *ndb_lg)
10023 ndb_lg->setName(alter_info->logfile_group_name);
10024 ndb_lg->setUndoBufferSize(alter_info->undo_buffer_size);
10025 return FALSE;
10028 bool set_up_undofile(st_alter_tablespace *alter_info,
10029 NdbDictionary::Undofile *ndb_uf)
10031 ndb_uf->setPath(alter_info->undo_file_name);
10032 ndb_uf->setSize(alter_info->initial_size);
10033 ndb_uf->setLogfileGroup(alter_info->logfile_group_name);
10034 return FALSE;
10037 int ndbcluster_alter_tablespace(handlerton *hton,
10038 THD* thd, st_alter_tablespace *alter_info)
10040 int is_tablespace= 0;
10041 NdbError err;
10042 NDBDICT *dict;
10043 int error;
10044 const char *errmsg;
10045 Ndb *ndb;
10046 DBUG_ENTER("ha_ndbcluster::alter_tablespace");
10047 LINT_INIT(errmsg);
10049 ndb= check_ndb_in_thd(thd);
10050 if (ndb == NULL)
10052 DBUG_RETURN(HA_ERR_NO_CONNECTION);
10054 dict= ndb->getDictionary();
10056 switch (alter_info->ts_cmd_type){
10057 case (CREATE_TABLESPACE):
10059 error= ER_CREATE_FILEGROUP_FAILED;
10061 NdbDictionary::Tablespace ndb_ts;
10062 NdbDictionary::Datafile ndb_df;
10063 NdbDictionary::ObjectId objid;
10064 if (set_up_tablespace(alter_info, &ndb_ts))
10066 DBUG_RETURN(1);
10068 if (set_up_datafile(alter_info, &ndb_df))
10070 DBUG_RETURN(1);
10072 errmsg= "TABLESPACE";
10073 if (dict->createTablespace(ndb_ts, &objid))
10075 DBUG_PRINT("error", ("createTablespace returned %d", error));
10076 goto ndberror;
10078 DBUG_PRINT("alter_info", ("Successfully created Tablespace"));
10079 errmsg= "DATAFILE";
10080 if (dict->createDatafile(ndb_df))
10082 err= dict->getNdbError();
10083 NdbDictionary::Tablespace tmp= dict->getTablespace(ndb_ts.getName());
10084 if (dict->getNdbError().code == 0 &&
10085 tmp.getObjectId() == objid.getObjectId() &&
10086 tmp.getObjectVersion() == objid.getObjectVersion())
10088 dict->dropTablespace(tmp);
10091 DBUG_PRINT("error", ("createDatafile returned %d", error));
10092 goto ndberror2;
10094 is_tablespace= 1;
10095 break;
10097 case (ALTER_TABLESPACE):
10099 error= ER_ALTER_FILEGROUP_FAILED;
10100 if (alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_ADD_FILE)
10102 NdbDictionary::Datafile ndb_df;
10103 if (set_up_datafile(alter_info, &ndb_df))
10105 DBUG_RETURN(1);
10107 errmsg= " CREATE DATAFILE";
10108 if (dict->createDatafile(ndb_df))
10110 goto ndberror;
10113 else if(alter_info->ts_alter_tablespace_type == ALTER_TABLESPACE_DROP_FILE)
10115 NdbDictionary::Tablespace ts= dict->getTablespace(alter_info->tablespace_name);
10116 NdbDictionary::Datafile df= dict->getDatafile(0, alter_info->data_file_name);
10117 NdbDictionary::ObjectId objid;
10118 df.getTablespaceId(&objid);
10119 if (ts.getObjectId() == objid.getObjectId() &&
10120 strcmp(df.getPath(), alter_info->data_file_name) == 0)
10122 errmsg= " DROP DATAFILE";
10123 if (dict->dropDatafile(df))
10125 goto ndberror;
10128 else
10130 DBUG_PRINT("error", ("No such datafile"));
10131 my_error(ER_ALTER_FILEGROUP_FAILED, MYF(0), " NO SUCH FILE");
10132 DBUG_RETURN(1);
10135 else
10137 DBUG_PRINT("error", ("Unsupported alter tablespace: %d",
10138 alter_info->ts_alter_tablespace_type));
10139 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
10141 is_tablespace= 1;
10142 break;
10144 case (CREATE_LOGFILE_GROUP):
10146 error= ER_CREATE_FILEGROUP_FAILED;
10147 NdbDictionary::LogfileGroup ndb_lg;
10148 NdbDictionary::Undofile ndb_uf;
10149 NdbDictionary::ObjectId objid;
10150 if (alter_info->undo_file_name == NULL)
10153 REDO files in LOGFILE GROUP not supported yet
10155 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
10157 if (set_up_logfile_group(alter_info, &ndb_lg))
10159 DBUG_RETURN(1);
10161 errmsg= "LOGFILE GROUP";
10162 if (dict->createLogfileGroup(ndb_lg, &objid))
10164 goto ndberror;
10166 DBUG_PRINT("alter_info", ("Successfully created Logfile Group"));
10167 if (set_up_undofile(alter_info, &ndb_uf))
10169 DBUG_RETURN(1);
10171 errmsg= "UNDOFILE";
10172 if (dict->createUndofile(ndb_uf))
10174 err= dict->getNdbError();
10175 NdbDictionary::LogfileGroup tmp= dict->getLogfileGroup(ndb_lg.getName());
10176 if (dict->getNdbError().code == 0 &&
10177 tmp.getObjectId() == objid.getObjectId() &&
10178 tmp.getObjectVersion() == objid.getObjectVersion())
10180 dict->dropLogfileGroup(tmp);
10182 goto ndberror2;
10184 break;
10186 case (ALTER_LOGFILE_GROUP):
10188 error= ER_ALTER_FILEGROUP_FAILED;
10189 if (alter_info->undo_file_name == NULL)
10192 REDO files in LOGFILE GROUP not supported yet
10194 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
10196 NdbDictionary::Undofile ndb_uf;
10197 if (set_up_undofile(alter_info, &ndb_uf))
10199 DBUG_RETURN(1);
10201 errmsg= "CREATE UNDOFILE";
10202 if (dict->createUndofile(ndb_uf))
10204 goto ndberror;
10206 break;
10208 case (DROP_TABLESPACE):
10210 error= ER_DROP_FILEGROUP_FAILED;
10211 errmsg= "TABLESPACE";
10212 if (dict->dropTablespace(dict->getTablespace(alter_info->tablespace_name)))
10214 goto ndberror;
10216 is_tablespace= 1;
10217 break;
10219 case (DROP_LOGFILE_GROUP):
10221 error= ER_DROP_FILEGROUP_FAILED;
10222 errmsg= "LOGFILE GROUP";
10223 if (dict->dropLogfileGroup(dict->getLogfileGroup(alter_info->logfile_group_name)))
10225 goto ndberror;
10227 break;
10229 case (CHANGE_FILE_TABLESPACE):
10231 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
10233 case (ALTER_ACCESS_MODE_TABLESPACE):
10235 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
10237 default:
10239 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
10242 #ifdef HAVE_NDB_BINLOG
10243 if (is_tablespace)
10244 ndbcluster_log_schema_op(thd, 0,
10245 thd->query(), thd->query_length(),
10246 "", alter_info->tablespace_name,
10247 0, 0,
10248 SOT_TABLESPACE, 0, 0, 0);
10249 else
10250 ndbcluster_log_schema_op(thd, 0,
10251 thd->query(), thd->query_length(),
10252 "", alter_info->logfile_group_name,
10253 0, 0,
10254 SOT_LOGFILE_GROUP, 0, 0, 0);
10255 #endif
10256 DBUG_RETURN(FALSE);
10258 ndberror:
10259 err= dict->getNdbError();
10260 ndberror2:
10261 set_ndb_err(thd, err);
10262 ndb_to_mysql_error(&err);
10264 my_error(error, MYF(0), errmsg);
10265 DBUG_RETURN(1);
10269 bool ha_ndbcluster::get_no_parts(const char *name, uint *no_parts)
10271 Ndb *ndb;
10272 NDBDICT *dict;
10273 int err;
10274 DBUG_ENTER("ha_ndbcluster::get_no_parts");
10275 LINT_INIT(err);
10277 set_dbname(name);
10278 set_tabname(name);
10279 for (;;)
10281 if (check_ndb_connection())
10283 err= HA_ERR_NO_CONNECTION;
10284 break;
10286 ndb= get_ndb();
10287 ndb->setDatabaseName(m_dbname);
10288 Ndb_table_guard ndbtab_g(dict= ndb->getDictionary(), m_tabname);
10289 if (!ndbtab_g.get_table())
10290 ERR_BREAK(dict->getNdbError(), err);
10291 *no_parts= ndbtab_g.get_table()->getFragmentCount();
10292 DBUG_RETURN(FALSE);
10295 print_error(err, MYF(0));
10296 DBUG_RETURN(TRUE);
10299 static int ndbcluster_fill_files_table(handlerton *hton,
10300 THD *thd,
10301 TABLE_LIST *tables,
10302 COND *cond)
10304 TABLE* table= tables->table;
10305 Ndb *ndb= check_ndb_in_thd(thd);
10306 NdbDictionary::Dictionary* dict= ndb->getDictionary();
10307 NdbDictionary::Dictionary::List dflist;
10308 NdbError ndberr;
10309 uint i;
10310 DBUG_ENTER("ndbcluster_fill_files_table");
10312 dict->listObjects(dflist, NdbDictionary::Object::Datafile);
10313 ndberr= dict->getNdbError();
10314 if (ndberr.classification != NdbError::NoError)
10315 ERR_RETURN(ndberr);
10317 for (i= 0; i < dflist.count; i++)
10319 NdbDictionary::Dictionary::List::Element& elt = dflist.elements[i];
10320 Ndb_cluster_connection_node_iter iter;
10321 uint id;
10323 g_ndb_cluster_connection->init_get_next_node(iter);
10325 while ((id= g_ndb_cluster_connection->get_next_node(iter)))
10327 init_fill_schema_files_row(table);
10328 NdbDictionary::Datafile df= dict->getDatafile(id, elt.name);
10329 ndberr= dict->getNdbError();
10330 if(ndberr.classification != NdbError::NoError)
10332 if (ndberr.classification == NdbError::SchemaError)
10333 continue;
10335 if (ndberr.classification == NdbError::UnknownResultError)
10336 continue;
10338 ERR_RETURN(ndberr);
10340 NdbDictionary::Tablespace ts= dict->getTablespace(df.getTablespace());
10341 ndberr= dict->getNdbError();
10342 if (ndberr.classification != NdbError::NoError)
10344 if (ndberr.classification == NdbError::SchemaError)
10345 continue;
10346 ERR_RETURN(ndberr);
10349 table->field[IS_FILES_FILE_NAME]->set_notnull();
10350 table->field[IS_FILES_FILE_NAME]->store(elt.name, strlen(elt.name),
10351 system_charset_info);
10352 table->field[IS_FILES_FILE_TYPE]->set_notnull();
10353 table->field[IS_FILES_FILE_TYPE]->store("DATAFILE",8,
10354 system_charset_info);
10355 table->field[IS_FILES_TABLESPACE_NAME]->set_notnull();
10356 table->field[IS_FILES_TABLESPACE_NAME]->store(df.getTablespace(),
10357 strlen(df.getTablespace()),
10358 system_charset_info);
10359 table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
10360 table->field[IS_FILES_LOGFILE_GROUP_NAME]->
10361 store(ts.getDefaultLogfileGroup(),
10362 strlen(ts.getDefaultLogfileGroup()),
10363 system_charset_info);
10364 table->field[IS_FILES_ENGINE]->set_notnull();
10365 table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
10366 ndbcluster_hton_name_length,
10367 system_charset_info);
10369 table->field[IS_FILES_FREE_EXTENTS]->set_notnull();
10370 table->field[IS_FILES_FREE_EXTENTS]->store(df.getFree()
10371 / ts.getExtentSize());
10372 table->field[IS_FILES_TOTAL_EXTENTS]->set_notnull();
10373 table->field[IS_FILES_TOTAL_EXTENTS]->store(df.getSize()
10374 / ts.getExtentSize());
10375 table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
10376 table->field[IS_FILES_EXTENT_SIZE]->store(ts.getExtentSize());
10377 table->field[IS_FILES_INITIAL_SIZE]->set_notnull();
10378 table->field[IS_FILES_INITIAL_SIZE]->store(df.getSize());
10379 table->field[IS_FILES_MAXIMUM_SIZE]->set_notnull();
10380 table->field[IS_FILES_MAXIMUM_SIZE]->store(df.getSize());
10381 table->field[IS_FILES_VERSION]->set_notnull();
10382 table->field[IS_FILES_VERSION]->store(df.getObjectVersion());
10384 table->field[IS_FILES_ROW_FORMAT]->set_notnull();
10385 table->field[IS_FILES_ROW_FORMAT]->store("FIXED", 5, system_charset_info);
10387 char extra[30];
10388 int len= my_snprintf(extra, sizeof(extra), "CLUSTER_NODE=%u", id);
10389 table->field[IS_FILES_EXTRA]->set_notnull();
10390 table->field[IS_FILES_EXTRA]->store(extra, len, system_charset_info);
10391 schema_table_store_record(thd, table);
10395 NdbDictionary::Dictionary::List uflist;
10396 dict->listObjects(uflist, NdbDictionary::Object::Undofile);
10397 ndberr= dict->getNdbError();
10398 if (ndberr.classification != NdbError::NoError)
10399 ERR_RETURN(ndberr);
10401 for (i= 0; i < uflist.count; i++)
10403 NdbDictionary::Dictionary::List::Element& elt= uflist.elements[i];
10404 Ndb_cluster_connection_node_iter iter;
10405 unsigned id;
10407 g_ndb_cluster_connection->init_get_next_node(iter);
10409 while ((id= g_ndb_cluster_connection->get_next_node(iter)))
10411 NdbDictionary::Undofile uf= dict->getUndofile(id, elt.name);
10412 ndberr= dict->getNdbError();
10413 if (ndberr.classification != NdbError::NoError)
10415 if (ndberr.classification == NdbError::SchemaError)
10416 continue;
10417 if (ndberr.classification == NdbError::UnknownResultError)
10418 continue;
10419 ERR_RETURN(ndberr);
10421 NdbDictionary::LogfileGroup lfg=
10422 dict->getLogfileGroup(uf.getLogfileGroup());
10423 ndberr= dict->getNdbError();
10424 if (ndberr.classification != NdbError::NoError)
10426 if (ndberr.classification == NdbError::SchemaError)
10427 continue;
10428 ERR_RETURN(ndberr);
10431 init_fill_schema_files_row(table);
10432 table->field[IS_FILES_FILE_NAME]->set_notnull();
10433 table->field[IS_FILES_FILE_NAME]->store(elt.name, strlen(elt.name),
10434 system_charset_info);
10435 table->field[IS_FILES_FILE_TYPE]->set_notnull();
10436 table->field[IS_FILES_FILE_TYPE]->store("UNDO LOG", 8,
10437 system_charset_info);
10438 NdbDictionary::ObjectId objid;
10439 uf.getLogfileGroupId(&objid);
10440 table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
10441 table->field[IS_FILES_LOGFILE_GROUP_NAME]->store(uf.getLogfileGroup(),
10442 strlen(uf.getLogfileGroup()),
10443 system_charset_info);
10444 table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->set_notnull();
10445 table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->store(objid.getObjectId());
10446 table->field[IS_FILES_ENGINE]->set_notnull();
10447 table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
10448 ndbcluster_hton_name_length,
10449 system_charset_info);
10451 table->field[IS_FILES_TOTAL_EXTENTS]->set_notnull();
10452 table->field[IS_FILES_TOTAL_EXTENTS]->store(uf.getSize()/4);
10453 table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
10454 table->field[IS_FILES_EXTENT_SIZE]->store(4);
10456 table->field[IS_FILES_INITIAL_SIZE]->set_notnull();
10457 table->field[IS_FILES_INITIAL_SIZE]->store(uf.getSize());
10458 table->field[IS_FILES_MAXIMUM_SIZE]->set_notnull();
10459 table->field[IS_FILES_MAXIMUM_SIZE]->store(uf.getSize());
10461 table->field[IS_FILES_VERSION]->set_notnull();
10462 table->field[IS_FILES_VERSION]->store(uf.getObjectVersion());
10464 char extra[100];
10465 int len= my_snprintf(extra,sizeof(extra),"CLUSTER_NODE=%u;UNDO_BUFFER_SIZE=%lu",
10466 id, (ulong) lfg.getUndoBufferSize());
10467 table->field[IS_FILES_EXTRA]->set_notnull();
10468 table->field[IS_FILES_EXTRA]->store(extra, len, system_charset_info);
10469 schema_table_store_record(thd, table);
10473 // now for LFGs
10474 NdbDictionary::Dictionary::List lfglist;
10475 dict->listObjects(lfglist, NdbDictionary::Object::LogfileGroup);
10476 ndberr= dict->getNdbError();
10477 if (ndberr.classification != NdbError::NoError)
10478 ERR_RETURN(ndberr);
10480 for (i= 0; i < lfglist.count; i++)
10482 NdbDictionary::Dictionary::List::Element& elt= lfglist.elements[i];
10484 NdbDictionary::LogfileGroup lfg= dict->getLogfileGroup(elt.name);
10485 ndberr= dict->getNdbError();
10486 if (ndberr.classification != NdbError::NoError)
10488 if (ndberr.classification == NdbError::SchemaError)
10489 continue;
10490 ERR_RETURN(ndberr);
10493 init_fill_schema_files_row(table);
10494 table->field[IS_FILES_FILE_TYPE]->set_notnull();
10495 table->field[IS_FILES_FILE_TYPE]->store("UNDO LOG", 8,
10496 system_charset_info);
10498 table->field[IS_FILES_LOGFILE_GROUP_NAME]->set_notnull();
10499 table->field[IS_FILES_LOGFILE_GROUP_NAME]->store(elt.name,
10500 strlen(elt.name),
10501 system_charset_info);
10502 table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->set_notnull();
10503 table->field[IS_FILES_LOGFILE_GROUP_NUMBER]->store(lfg.getObjectId());
10504 table->field[IS_FILES_ENGINE]->set_notnull();
10505 table->field[IS_FILES_ENGINE]->store(ndbcluster_hton_name,
10506 ndbcluster_hton_name_length,
10507 system_charset_info);
10509 table->field[IS_FILES_FREE_EXTENTS]->set_notnull();
10510 table->field[IS_FILES_FREE_EXTENTS]->store(lfg.getUndoFreeWords());
10511 table->field[IS_FILES_EXTENT_SIZE]->set_notnull();
10512 table->field[IS_FILES_EXTENT_SIZE]->store(4);
10514 table->field[IS_FILES_VERSION]->set_notnull();
10515 table->field[IS_FILES_VERSION]->store(lfg.getObjectVersion());
10517 char extra[100];
10518 int len= my_snprintf(extra,sizeof(extra),
10519 "UNDO_BUFFER_SIZE=%lu",
10520 (ulong) lfg.getUndoBufferSize());
10521 table->field[IS_FILES_EXTRA]->set_notnull();
10522 table->field[IS_FILES_EXTRA]->store(extra, len, system_charset_info);
10523 schema_table_store_record(thd, table);
10525 DBUG_RETURN(0);
10528 SHOW_VAR ndb_status_variables_export[]= {
10529 {"Ndb", (char*) &ndb_status_variables, SHOW_ARRAY},
10530 {NullS, NullS, SHOW_LONG}
10533 struct st_mysql_storage_engine ndbcluster_storage_engine=
10534 { MYSQL_HANDLERTON_INTERFACE_VERSION };
10536 mysql_declare_plugin(ndbcluster)
10538 MYSQL_STORAGE_ENGINE_PLUGIN,
10539 &ndbcluster_storage_engine,
10540 ndbcluster_hton_name,
10541 "MySQL AB",
10542 "Clustered, fault-tolerant tables",
10543 PLUGIN_LICENSE_GPL,
10544 ndbcluster_init, /* Plugin Init */
10545 NULL, /* Plugin Deinit */
10546 0x0100 /* 1.0 */,
10547 ndb_status_variables_export,/* status variables */
10548 NULL, /* system variables */
10549 NULL /* config options */
10551 mysql_declare_plugin_end;
10553 #endif