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 */
20 This file defines the NDB Cluster handler: the interface between
24 #ifdef USE_PRAGMA_IMPLEMENTATION
25 #pragma implementation // gcc: Class implementation
28 #include "mysql_priv.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>
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)
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
58 extern void ndb_init_internal();
59 extern void ndb_end_internal();
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
*,
84 static int ndbcluster_alter_tablespace(handlerton
*hton
,
86 st_alter_tablespace
*info
);
87 static int ndbcluster_fill_files_table(handlerton
*hton
,
92 handlerton
*ndbcluster_hton
;
94 static handler
*ndbcluster_create_handler(handlerton
*hton
,
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
)
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); \
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
);
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
{
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();
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
;
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
:
236 /* Mapping missing, go with the ndb error code*/
240 /* Mapping exists, go with the mapped code */
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");
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");
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)
268 const NdbError
&err
= trans
->getNdbError();
269 if (err
.classification
!= NdbError::NoError
&&
270 err
.classification
!= NdbError::ConstraintViolation
&&
271 err
.classification
!= NdbError::NoDataFound
)
278 int execute_no_commit(ha_ndbcluster
*h
, NdbTransaction
*trans
,
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
,
290 int execute_commit(ha_ndbcluster
*h
, NdbTransaction
*trans
)
292 return trans
->execute(NdbTransaction::Commit
,
293 NdbOperation::AbortOnError
,
298 int execute_commit(THD
*thd
, NdbTransaction
*trans
)
300 return trans
->execute(NdbTransaction::Commit
,
301 NdbOperation::AbortOnError
,
302 thd
->variables
.ndb_force_send
);
306 int execute_no_commit_ie(ha_ndbcluster
*h
, NdbTransaction
*trans
,
309 h
->release_completed_operations(trans
, force_release
);
310 return trans
->execute(NdbTransaction::NoCommit
,
311 NdbOperation::AO_IgnoreError
,
316 Place holder for ha_ndbcluster thread specific data
318 typedef struct st_thd_ndb_share
{
320 struct Ndb_local_table_statistics stat
;
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
;
332 ndb
= new Ndb(g_ndb_cluster_connection
, "");
339 query_state
&= NDB_QUERY_NORMAL
;
341 (void) hash_init(&open_tables
, &my_charset_bin
, 5, 0, 0,
342 (hash_get_key
)thd_ndb_share_get_key
, 0, 0);
350 Ndb::Free_list_usage tmp
;
352 while (ndb
->get_free_list_usage(&tmp
))
354 uint leaked
= (uint
) tmp
.m_created
- tmp
.m_free
;
356 fprintf(stderr
, "NDB: Found %u %s%s that %s not been released\n",
358 (leaked
== 1)?"":"'s",
359 (leaked
== 1)?"has":"have");
365 changed_tables
.empty();
366 hash_free(&open_tables
);
370 Thd_ndb::init_open_tables()
375 my_hash_reset(&open_tables
);
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;
398 ha_rows
ha_ndbcluster::records()
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
));
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
;
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
)
430 DBUG_ENTER("ha_ndbcluster::records_update");
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
));
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
);
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;
458 stats
.records
= local_info
->records
+ local_info
->no_uncommitted_rows_count
;
462 void ha_ndbcluster::no_uncommitted_rows_execute_failure()
464 if (m_ha_not_exact_count
)
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;
472 void ha_ndbcluster::no_uncommitted_rows_update(int c
)
474 if (m_ha_not_exact_count
)
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
));
485 void ha_ndbcluster::no_uncommitted_rows_reset(THD
*thd
)
487 if (m_ha_not_exact_count
)
489 DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_reset");
490 Thd_ndb
*thd_ndb
= get_thd_ndb(thd
);
492 thd_ndb
->m_error
= FALSE
;
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
501 static void set_ndb_err(THD
*thd
, const NdbError
&err
)
503 DBUG_ENTER("set_ndb_err");
506 Thd_ndb
*thd_ndb
= get_thd_ndb(thd
);
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
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
)
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");
527 thd_ndb
->m_query_id
= thd
->query_id
;
528 thd_ndb
->m_error_code
= err
.code
;
532 int ha_ndbcluster::ndb_err(NdbTransaction
*trans
)
534 THD
*thd
= current_thd
;
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
);
557 res
= ndb_to_mysql_error(&err
);
558 DBUG_PRINT("info", ("transformed ndbcluster error %d to mysql error %d",
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
;
573 (char *) unique_index
->getObjectId() == error_data
)
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
;
591 /* We are batching inserts, offending key is not available */
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
,
607 DBUG_ENTER("ha_ndbcluster::get_error_message");
608 DBUG_PRINT("enter", ("error: %d", error
));
610 Ndb
*ndb
= check_ndb_in_thd(current_thd
);
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
);
624 Check if type is supported by NDB.
627 static bool ndb_supported_type(enum_field_types 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
:
655 case MYSQL_TYPE_GEOMETRY
:
657 case MYSQL_TYPE_NULL
:
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
)
671 case MYSQL_TYPE_VAR_STRING
:
672 case MYSQL_TYPE_VARCHAR
:
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
:
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(),
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
740 pack_len
= sizeof(empty_field
);
741 field_ptr
= (uchar
*)&empty_field
;
742 if (field
->is_null(row_offset
))
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"));
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
))
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
);
777 DBUG_RETURN(ndb_op
->setValue(fieldnr
, (char*)&bits
) != 0);
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));
805 *set_blob_value
= TRUE
;
806 // No callback needed to write value
807 DBUG_RETURN(ndb_blob
->setValue(blob_ptr
, blob_len
) != 0);
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.
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
)
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
,
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
++)
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
))
864 if (value
.blob
== NULL
)
866 DBUG_PRINT("info",("[%u] skipped", i
));
869 Field_blob
*field_blob
= (Field_blob
*)field
;
870 NdbBlob
*ndb_blob
= value
.blob
;
872 if (ndb_blob
->getNull(isNull
) != 0)
873 ERR_RETURN(ndb_blob
->getNdbError());
876 if (ndb_blob
->getLength(len64
) != 0)
877 ERR_RETURN(ndb_blob
->getNdbError());
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
);
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
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
));
909 DBUG_PRINT("info", ("allocate blobs buffer size %u", offset
));
910 buffer
= (uchar
*) my_malloc(offset
, MYF(MY_WME
));
913 sql_print_error("ha_ndbcluster::get_ndb_blobs_value: "
914 "my_malloc(%u) failed", offset
);
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)));
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
)
948 if (field
->pack_length() != 0)
949 field_buf
= buf
+ (field
->ptr
- table
->record
[0]);
951 field_buf
= (uchar
*)&dummy_buf
;
952 m_value
[fieldnr
].rec
= ndb_op
->getValue(fieldnr
,
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
);
963 NdbBlob
*ndb_blob
= ndb_op
->getBlobHandle(fieldnr
);
964 m_value
[fieldnr
].blob
= ndb_blob
;
965 if (ndb_blob
!= NULL
)
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);
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()
997 uint
*blob_index
, *blob_index_end
;
998 if (table_share
->blob_fields
== 0)
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
))
1008 } while (++blob_index
!= blob_index_end
);
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.
1022 -2 Meta data has changed; Re-read data and try again
1025 int cmp_frm(const NDBTAB
*ndbtab
, const void *pack_data
,
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
)))
1038 int ha_ndbcluster::get_metadata(const char *path
)
1040 Ndb
*ndb
= get_ndb();
1041 NDBDICT
*dict
= ndb
->getDictionary();
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.
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
));
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
))
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));
1086 DBUG_PRINT("info", ("fetched table %s", tab
->getName()));
1088 if ((error
= open_indexes(ndb
, table
, FALSE
)) == 0)
1094 ndbtab_g
.invalidate();
1099 static int fix_unique_index_attr_order(NDB_INDEX_DATA
&data
,
1100 const NDBINDEX
*index
,
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",
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
;
1123 data
.unique_index_attrid_map
[i
]= 255;
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
;
1134 DBUG_ASSERT(data
.unique_index_attrid_map
[i
] != 255);
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
)
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
);
1160 DBUG_PRINT("error", ("Failed to create index %u", i
));
1168 static void ndb_init_index(NDB_INDEX_DATA
&data
)
1170 data
.type
= UNDEFINED_INDEX
;
1171 data
.status
= UNDEFINED
;
1172 data
.unique_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
)
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
);
1215 ERR_RETURN(dict
->getNdbError());
1216 DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d",
1218 index
->getObjectId(),
1219 index
->getObjectVersion() & 0xFFFFFF,
1220 index
->getObjectVersion() >> 24,
1221 index
->getObjectStatus()));
1222 DBUG_ASSERT(index
->getObjectStatus() ==
1223 NdbDictionary::Object::Retrieved
);
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
;
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",
1240 d
.index_stat_cache_entries
,
1241 d
.index_stat_update_freq
));
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
);
1259 ERR_RETURN(dict
->getNdbError());
1260 DBUG_PRINT("info", ("index: 0x%lx id: %d version: %d.%d status: %d",
1262 index
->getObjectId(),
1263 index
->getObjectVersion() & 0xFFFFFF,
1264 index
->getObjectVersion() >> 24,
1265 index
->getObjectStatus()));
1266 DBUG_ASSERT(index
->getObjectStatus() ==
1267 NdbDictionary::Object::Retrieved
);
1270 m_index
[index_no
].unique_index
= index
;
1271 error
= fix_unique_index_attr_order(m_index
[index_no
], index
, key_info
);
1274 m_index
[index_no
].status
= ACTIVE
;
1280 Associate index handles for each index of a table
1282 int ha_ndbcluster::open_indexes(Ndb
*ndb
, TABLE
*tab
, bool ignore_error
)
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
)))
1297 m_index
[i
].index
= m_index
[i
].unique_index
= NULL
;
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
)
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);
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
)
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",
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
];
1367 Drop all indexes that are marked for deletion
1369 int ha_ndbcluster::drop_indexes(Ndb
*ndb
, TABLE
*tab
)
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
;
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
);
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
);
1407 dict
->removeIndexGlobal(*unique_index
, 1);
1408 m_index
[i
].unique_index
= NULL
;
1413 ndb_clear_index(m_index
[i
]);
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
,
1435 bool is_hash_index
= (key_info
[inx
].algorithm
==
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
) :
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())
1461 void ha_ndbcluster::release_metadata(THD
*thd
, Ndb
*ndb
)
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
);
1481 DBUG_ASSERT(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
]);
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
||
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
1528 // HA_KEYREAD_ONLY |
1535 HA_ONLY_WHOLE_INDEX
,
1537 /* UNIQUE_ORDERED_INDEX */
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.
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);
1595 memmove(buf
+ 1, ptr
+ 2, pack_len
- 1);
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
;
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
;
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());
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
;
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
))
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
;
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());
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");
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
;
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
;
1703 int ha_ndbcluster::define_read_attrs(uchar
* buf
, NdbOperation
* op
)
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());
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
;
1730 const NDBTAB
*tab
= (const NDBTAB
*) m_table
;
1731 if (!tab
->getColumn(hidden_no
))
1734 if (get_ndb_value(op
, NULL
, hidden_no
, NULL
))
1735 ERR_RETURN(op
->getNdbError());
1742 Read one record from NDB using primary key.
1745 int ha_ndbcluster::pk_read(const uchar
*key
, uint key_len
, uchar
*buf
,
1748 uint no_fields
= table_share
->fields
;
1749 NdbConnection
*trans
= m_active_trans
;
1753 DBUG_ENTER("pk_read");
1754 DBUG_PRINT("enter", ("key_len: %u", key_len
));
1755 DBUG_DUMP("key", key
, key_len
);
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());
1778 if ((res
= set_primary_key(op
, key
)))
1782 if ((res
= define_read_attrs(buf
, op
)))
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
1810 Read one complementing record from NDB using primary key from old_data
1814 int ha_ndbcluster::complemented_read(const uchar
*old_data
, uchar
*new_data
,
1817 uint no_fields
= table_share
->fields
, i
;
1818 NdbTransaction
*trans
= m_active_trans
;
1820 DBUG_ENTER("complemented_read");
1823 if (bitmap_is_set_all(table
->read_set
))
1825 // We have allready retrieved all fields, nothing to complement
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());
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
);
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
;
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
,
1899 const NdbOperation
*op
= first
;
1900 DBUG_ENTER("ha_ndbcluster::check_all_operations_for_error");
1904 NdbError err
= op
->getNdbError();
1905 if (err
.status
!= NdbError::Success
)
1907 if (ndb_to_mysql_error(&err
) != (int) errcode
)
1909 if (op
== last
) break;
1910 op
= trans
->getNextCompletedOperation(op
);
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
)
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
;
1947 * Check if record contains any null valued columns that are part of a key
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
))
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
;
1983 const NdbOperation
*first
, *last
;
1986 DBUG_ENTER("peek_indexed_rows");
1988 NdbOperation::LockMode lm
=
1989 (NdbOperation::LockMode
)get_ndb_lock_type(m_lock
.type
);
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());
2001 if ((res
= set_primary_key_from_record(op
, record
)))
2002 ERR_RETURN(trans
->getNdbError());
2004 if (m_use_partition_function
)
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
);
2014 m_part_info
->err_value
= func_value
;
2017 op
->setPartitionId(part_id
);
2021 * Fetch any rows with colliding unique indexes
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"));
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
));
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());
2056 if ((res
= set_index_key_from_record(iop
, record
, i
)))
2057 ERR_RETURN(trans
->getNdbError());
2060 last
= trans
->getLastDefinedOperation();
2062 res
= execute_no_commit_ie(this,trans
,FALSE
);
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
));
2077 DBUG_PRINT("info", ("m_dupkey %d", m_dupkey
));
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
)
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
,
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
)))
2108 if ((res
= define_read_attrs(buf
, op
)))
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
;
2118 table
->status
= STATUS_GARBAGE
;
2123 // The value have now been fetched from NDB
2129 inline int ha_ndbcluster::fetch_next(NdbScanOperation
* cursor
)
2131 DBUG_ENTER("fetch_next");
2133 NdbTransaction
*trans
= m_active_trans
;
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
;
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());
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
;;
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
));
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
);
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
2195 DBUG_PRINT("info", ("ops_pending: %ld", (long) m_ops_pending
));
2198 if (m_transaction_on
)
2200 if (execute_no_commit(this,trans
,FALSE
) != 0)
2205 if (execute_commit(this,trans
) != 0)
2207 if (trans
->restart() != 0)
2215 contact_ndb
= (local_check
== 2);
2221 } while (local_check
== 2);
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.
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
)
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"));
2255 table
->status
= STATUS_NOT_FOUND
;
2257 DBUG_PRINT("info", ("No more records"));
2258 DBUG_RETURN(HA_ERR_END_OF_FILE
);
2262 DBUG_RETURN(ndb_err(m_active_trans
));
2267 Set bounds for ordered index scan.
2270 int ha_ndbcluster::set_bounds(NdbIndexScanOperation
*op
,
2273 const key_range
*keys
[2],
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];
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
];
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
;
2297 DBUG_PRINT("info", ("key %d not present", j
));
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
;
2308 uint part_len
= key_part
->length
;
2310 uint part_store_len
= key_part
->store_length
;
2311 // Info about each key part
2314 const key_range
*key
;
2315 const uchar
*part_ptr
;
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
];
2327 if (tot_len
< key_tot_len
[j
])
2329 p
.part_last
= (tot_len
+ part_store_len
>= key_tot_len
[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
;
2338 switch (p
.key
->flag
)
2340 case HA_READ_KEY_EXACT
:
2342 p
.bound_type
= NdbIndexScanOperation::BoundEQ
;
2343 else // differs for records_in_range
2344 p
.bound_type
= NdbIndexScanOperation::BoundLE
;
2347 case HA_READ_KEY_OR_NEXT
:
2348 p
.bound_type
= NdbIndexScanOperation::BoundLE
;
2350 case HA_READ_AFTER_KEY
:
2352 p
.bound_type
= NdbIndexScanOperation::BoundLE
;
2354 p
.bound_type
= NdbIndexScanOperation::BoundLT
;
2357 case HA_READ_PREFIX_LAST
: // weird
2358 p
.bound_type
= NdbIndexScanOperation::BoundEQ
;
2360 case HA_READ_PREFIX_LAST_OR_PREV
: // weird
2361 p
.bound_type
= NdbIndexScanOperation::BoundGE
;
2363 case HA_READ_BEFORE_KEY
:
2365 p
.bound_type
= NdbIndexScanOperation::BoundGE
;
2367 p
.bound_type
= NdbIndexScanOperation::BoundGT
;
2374 switch (p
.key
->flag
)
2377 case HA_READ_BEFORE_KEY
:
2379 p
.bound_type
= NdbIndexScanOperation::BoundGE
;
2381 p
.bound_type
= NdbIndexScanOperation::BoundGT
;
2383 case HA_READ_AFTER_KEY
: // weird
2384 p
.bound_type
= NdbIndexScanOperation::BoundGE
;
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
));
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
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
;
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
)
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
));
2467 // Check that sorted seems to be initialised
2468 DBUG_ASSERT(sorted
== 0 || sorted
== 1);
2470 if (m_active_cursor
== 0)
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
,
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
;
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
);
2507 if (m_cond
&& m_cond
->generate_scan_filter(op
))
2508 DBUG_RETURN(ndb_err(trans
));
2510 if ((res
= define_read_attrs(buf
, op
)))
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
));
2532 guess_scan_flags(NdbOperation::LockMode lm
,
2533 const NDBTAB
* tab
, const MY_BITMAP
* readset
)
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
));
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
;
2556 Unique index scan in NDB (full table scan with scan filter)
2559 int ha_ndbcluster::unique_index_scan(const KEY
* key_info
,
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());
2614 m_cond
= new ha_ndbcluster_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
)))
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
)
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
));
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
)))
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;
2708 bitmap_clear_bit(table
->read_set
, field
->field_index
);
2712 ("Trying to set next auto increment value to %s",
2713 llstr(next_val
, buff
)));
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
)
2720 ERR_RETURN(ndb
->getNdbError());
2726 Insert one record into NDB.
2728 int ha_ndbcluster::write_row(uchar
*record
)
2730 bool has_auto_increment
;
2732 NdbTransaction
*trans
= m_active_trans
;
2735 THD
*thd
= table
->in_use
;
2736 longlong func_value
= 0;
2737 DBUG_ENTER("ha_ndbcluster::write_row");
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
)
2750 m_skip_auto_increment
= FALSE
;
2751 if ((error
= update_auto_increment()))
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
);
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();
2786 ERR_RETURN(trans
->getNdbError());
2788 if (m_use_partition_function
)
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
);
2797 m_part_info
->err_value
= func_value
;
2800 op
->setPartitionId(part_id
);
2803 if (table_share
->primary_key
== MAX_KEY
)
2805 // Table has hidden primary key
2806 Ndb
*ndb
= get_ndb();
2808 uint retries
= NDB_AUTO_INCREMENT_RETRIES
;
2809 int retry_sleep
= 30; /* 30 milliseconds, transaction */
2812 Ndb_tuple_id_range_guard
g(m_share
);
2813 if (ndb
->getAutoIncrementValue(m_table
, g
.range
, auto_value
, 1) == -1)
2816 ndb
->getNdbError().status
== NdbError::TemporaryError
)
2818 my_sleep(retry_sleep
);
2821 ERR_RETURN(ndb
->getNdbError());
2825 if (set_hidden_key(op
, table_share
->fields
, (const uchar
*)&auto_value
))
2826 ERR_RETURN(op
->getNdbError());
2831 if ((error
= set_primary_key_from_record(op
, record
)))
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
)
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
);
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!
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
||
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
));
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)
2929 if ((has_auto_increment
) && (m_skip_auto_increment
))
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"));
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
))
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
))
2972 if (memcmp(old_row
+key_part
->offset
, new_row
+key_part
->offset
,
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
;
2991 uint32 old_part_id
= 0, new_part_id
= 0;
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");
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
);
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
,
3029 m_part_info
->err_value
= func_value
;
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
);
3047 DBUG_PRINT("info", ("read failed"));
3048 DBUG_RETURN(read_res
);
3051 m_primary_key_update
= TRUE
;
3052 delete_res
= delete_row(old_data
);
3053 m_primary_key_update
= FALSE
;
3056 DBUG_PRINT("info", ("delete failed"));
3057 DBUG_RETURN(delete_res
);
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
)))
3073 insert_res
= write_row(new_data
);
3074 m_primary_key_update
= FALSE
;
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
);
3084 push_warning(current_thd
,
3085 MYSQL_ERROR::WARN_LEVEL_WARN
,
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"));
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
)))
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
;
3120 if (uses_blob_value())
3121 m_blobs_pending
= TRUE
;
3122 if (m_use_partition_function
)
3123 cursor
->setPartitionId(new_part_id
);
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
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());
3148 if ((res
= set_primary_key_from_record(op
, old_data
)))
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
)
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
));
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
;
3222 DBUG_ENTER("delete_row");
3225 ha_statistic_increment(&SSV::ha_delete_count
);
3228 if (m_use_partition_function
&&
3229 (error
= get_part_for_delete(record
, table
->record
[0], m_part_info
,
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
;
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
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());
3297 if ((error
= set_primary_key_from_record(op
, record
)))
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
));
3326 Unpack a record read from NDB.
3328 @param buf Buffer to store read row
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
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
);
3358 p_field
++, value
++, field
= *p_field
)
3360 field
->set_notnull(row_offset
);
3363 if (!(field
->flags
& BLOB_FLAG
))
3365 int is_null
= (*value
).rec
->isNULL();
3370 DBUG_PRINT("info",("[%u] NULL",
3371 (*value
).rec
->getColumn()->getColumnNo()));
3372 field
->set_null(row_offset
);
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
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(),
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
),
3414 field_bit
->Field_bit::store((longlong
)
3415 (*value
).rec
->u_64_value(), TRUE
);
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());
3429 DBUG_PRINT("info",("[%u] SET",
3430 (*value
).rec
->getColumn()->getColumnNo()));
3431 DBUG_DUMP("info", field
->ptr
, field
->pack_length());
3436 NdbBlob
*ndb_blob
= (*value
).blob
;
3437 uint col_no
= ndb_blob
->getColumn()->getColumnNo();
3439 ndb_blob
->getDefined(isNull
);
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
);
3453 // pointer vas set in get_ndb_blobs_value
3454 Field_blob
*field_blob
= (Field_blob
*)field
;
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
));
3465 dbug_tmp_restore_column_map(table
->write_set
, old_map
);
3469 void ha_ndbcluster::unpack_record(uchar
*buf
)
3471 ndb_unpack_record(table
, m_value
, 0, buf
);
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
;
3480 const NDBCOL
*hidden_col
= tab
->getColumn(hidden_no
);
3481 const NdbRecAttr
* rec
= m_value
[hidden_no
].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(););
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");
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 */
3516 field
= table
->field
[f
];
3517 if (!(value
= m_value
[f
]).ptr
)
3519 strmov(buf
, "not read");
3525 if (! (field
->flags
& BLOB_FLAG
))
3527 if (value
.rec
->isNULL())
3529 strmov(buf
, "NULL");
3534 field
->sql_type(type
);
3535 field
->val_str(&val
);
3536 my_snprintf(buf
, sizeof(buf
), "%s %s", type
.c_ptr(), val
.c_ptr());
3540 NdbBlob
*ndb_blob
= value
.blob
;
3542 ndb_blob
->getNull(isNull
);
3544 strmov(buf
, "NULL");
3548 DBUG_PRINT("value", ("%u,%s: %s", f
, field
->field_name
, buf
));
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
;
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
;
3571 int ha_ndbcluster::index_end()
3573 DBUG_ENTER("ha_ndbcluster::index_end");
3574 DBUG_RETURN(close_scan());
3578 Check if key contains null.
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
)
3594 key
+= curr_part
->store_length
;
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
));
3610 start_key
.length
= key_len
;
3611 start_key
.flag
= find_flag
;
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
:
3623 DBUG_RETURN(read_range_first_to_buf(&start_key
, 0, descending
,
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
,
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
;
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.
3708 case PRIMARY_KEY_ORDERED_INDEX
:
3709 case PRIMARY_KEY_INDEX
:
3711 start_key
->length
== key_info
->key_length
&&
3712 start_key
->flag
== HA_READ_KEY_EXACT
)
3714 if (m_active_cursor
&& (error
= close_scan()))
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
);
3721 case UNIQUE_ORDERED_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()))
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
,
3742 // Start the ordered index scan and fetch the first row
3743 DBUG_RETURN(ordered_index_scan(start_key
, end_key
, sorted
, desc
, buf
,
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
,
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
3774 if (cursor
->restart(m_force_send
) != 0)
3780 index_init(table_share
->primary_key
, 0);
3784 int ha_ndbcluster::close_scan()
3786 NdbTransaction
*trans
= m_active_trans
;
3787 DBUG_ENTER("close_scan");
3790 if (!m_active_cursor
&& !m_multi_cursor
)
3793 NdbScanOperation
*cursor
= m_active_cursor
? m_active_cursor
: m_multi_cursor
;
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
3805 DBUG_PRINT("info", ("Keeping lock on scanned row"));
3807 if (!(op
= cursor
->lockCurrentTuple()))
3809 m_lock_tuple
= FALSE
;
3810 ERR_RETURN(trans
->getNdbError());
3814 m_lock_tuple
= FALSE
;
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
));
3829 cursor
->close(m_force_send
, TRUE
);
3830 m_active_cursor
= m_multi_cursor
= NULL
;
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
);
3882 KEY
*key_info
= table
->key_info
+ table_share
->primary_key
;
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
)
3907 KEY_PART_INFO
*key_part
;
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
;
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
) {
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
3946 memcpy(buff
+2, ptr
+ 1, len
);
3950 memcpy(buff
, ptr
, len
+ 2);
3956 memcpy(buff
, ptr
, len
);
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
));
3973 key_length
= ref_length
;
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
);
3982 memcpy(ref
, m_ref
, key_length
);
3985 if (table_share
->primary_key
== MAX_KEY
&& m_use_partition_function
)
3986 DBUG_DUMP("key+part", ref
, key_length
+sizeof(m_part_id
));
3988 DBUG_DUMP("ref", ref
, key_length
);
3993 int ha_ndbcluster::info(uint flag
)
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"));
4010 if (m_ha_not_exact_count
)
4013 result
= records_update();
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
))
4030 stats
.mean_rec_length
= stat
.row_size
;
4031 stats
.data_file_length
= stat
.fragment_memory
;
4032 stats
.records
= stat
.row_count
;
4036 stats
.mean_rec_length
= 0;
4041 if (flag
& HA_STATUS_CONST
)
4043 DBUG_PRINT("info", ("HA_STATUS_CONST"));
4046 if (flag
& HA_STATUS_ERRKEY
)
4048 DBUG_PRINT("info", ("HA_STATUS_ERRKEY"));
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;
4071 stats
.auto_increment_value
= (ulonglong
)auto_increment_value64
;
4076 result
= HA_ERR_NO_CONNECTION
;
4078 DBUG_RETURN(result
);
4082 void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO
*stat_info
,
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
));
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
;
4104 case HA_EXTRA_NO_IGNORE_DUP_KEY
:
4105 DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY"));
4106 m_ignore_dup_key
= FALSE
;
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
;
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
;
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"));
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"));
4132 case HA_EXTRA_DELETE_CANNOT_BATCH
:
4133 DBUG_PRINT("info", ("HA_EXTRA_DELETE_CANNOT_BATCH"));
4134 m_delete_cannot_batch
= TRUE
;
4136 case HA_EXTRA_UPDATE_CANNOT_BATCH
:
4137 DBUG_PRINT("info", ("HA_EXTRA_UPDATE_CANNOT_BATCH"));
4138 m_update_cannot_batch
= TRUE
;
4148 int ha_ndbcluster::reset()
4150 DBUG_ENTER("ha_ndbcluster::reset");
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
4162 bitmap_set_all(&m_part_info
->used_partitions
);
4164 /* reset flags set by extra calls */
4165 m_ignore_dup_key
= FALSE
;
4167 m_ignore_no_key
= FALSE
;
4168 m_delete_cannot_batch
= FALSE
;
4169 m_update_cannot_batch
= FALSE
;
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.
4181 rows number of rows to insert, 0 if unknown
4184 void ha_ndbcluster::start_bulk_insert(ha_rows rows
)
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
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;
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
;
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
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
;
4234 int ha_ndbcluster::end_bulk_insert()
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
;
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
);
4258 if (execute_commit(this, trans
) != 0)
4260 no_uncommitted_rows_execute_failure();
4261 my_errno
= error
= ndb_err(trans
);
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;
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
[] = {
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",
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
,
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
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
)
4345 m_lock
.type
=lock_type
;
4349 DBUG_PRINT("exit", ("lock_type: %d", lock_type
));
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")); \
4364 #define PRINT_OPTION_FLAGS(t)
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()))
4399 NdbOperation
*op
= 0;
4401 r
|= (op
= trans
->getNdbOperation(ndbtab
)) == 0;
4402 DBUG_ASSERT(r
== 0);
4404 r
|= op
->updateTuple();
4406 r
|= op
->writeTuple();
4407 DBUG_ASSERT(r
== 0);
4409 r
|= op
->equal(0u, (Uint32
)thd
->server_id
);
4410 DBUG_ASSERT(r
== 0);
4414 r
|= op
->setValue(1u, (Uint64
)0);
4415 DBUG_ASSERT(r
== 0);
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);
4425 r
|= op
->setValue(3u, (Uint64
)active_mi
->rli
.group_master_log_pos
);
4426 DBUG_ASSERT(r
== 0);
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);
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
;
4448 m_transaction_on
= thd
->variables
.ndb_use_transactions
;
4451 int ha_ndbcluster::start_statement(THD
*thd
,
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
))
4489 DBUG_PRINT("info", ("Locking the table..." ));
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
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
;
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
));
4545 mem_alloc_error(sizeof(THD_NDB_SHARE
));
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
;
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
;
4575 int ha_ndbcluster::external_lock(THD
*thd
, int lock_type
)
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
))
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
)))
4604 if ((error
= init_handler_for_statement(thd
, thd_ndb
)))
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
)))
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
;
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
;
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"));
4673 DBUG_PRINT("warning", ("ops_pending != 0L"));
4678 thd_ndb
->lock_count
--;
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
;
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
)
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
)))
4719 if ((error
= init_handler_for_statement(thd
, thd_ndb
)))
4723 thd_ndb
->start_stmt_count
--;
4729 Commit a transaction started in NDB.
4732 static int ndbcluster_commit(handlerton
*hton
, THD
*thd
, bool all
)
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");
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
4757 DBUG_PRINT("info", ("Commit before start or end-of-statement only"));
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
);
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 */
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();
4801 Rollback a transaction started in NDB.
4804 static int ndbcluster_rollback(handlerton
*hton
, THD
*thd
, bool all
)
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");
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"));
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
);
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();
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.
4850 Returns 0 or mysql error code.
4853 static int create_ndb_column(NDBCOL
&col
,
4855 HA_CREATE_INFO
*info
)
4858 if (col
.setName(field
->field_name
))
4860 return (my_errno
= errno
);
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
) {
4868 case MYSQL_TYPE_TINY
:
4869 if (field
->flags
& UNSIGNED_FLAG
)
4870 col
.setType(NDBCOL::Tinyunsigned
);
4872 col
.setType(NDBCOL::Tinyint
);
4875 case MYSQL_TYPE_SHORT
:
4876 if (field
->flags
& UNSIGNED_FLAG
)
4877 col
.setType(NDBCOL::Smallunsigned
);
4879 col
.setType(NDBCOL::Smallint
);
4882 case MYSQL_TYPE_LONG
:
4883 if (field
->flags
& UNSIGNED_FLAG
)
4884 col
.setType(NDBCOL::Unsigned
);
4886 col
.setType(NDBCOL::Int
);
4889 case MYSQL_TYPE_INT24
:
4890 if (field
->flags
& UNSIGNED_FLAG
)
4891 col
.setType(NDBCOL::Mediumunsigned
);
4893 col
.setType(NDBCOL::Mediumint
);
4896 case MYSQL_TYPE_LONGLONG
:
4897 if (field
->flags
& UNSIGNED_FLAG
)
4898 col
.setType(NDBCOL::Bigunsigned
);
4900 col
.setType(NDBCOL::Bigint
);
4903 case MYSQL_TYPE_FLOAT
:
4904 col
.setType(NDBCOL::Float
);
4907 case MYSQL_TYPE_DOUBLE
:
4908 col
.setType(NDBCOL::Double
);
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);
4923 col
.setType(NDBCOL::Olddecimal
);
4924 precision
-= 1 + (scale
> 0);
4926 col
.setPrecision(precision
);
4927 col
.setScale(scale
);
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
);
4942 col
.setType(NDBCOL::Decimal
);
4944 col
.setPrecision(precision
);
4945 col
.setScale(scale
);
4950 case MYSQL_TYPE_DATETIME
:
4951 col
.setType(NDBCOL::Datetime
);
4954 case MYSQL_TYPE_DATE
: // ?
4955 col
.setType(NDBCOL::Char
);
4956 col
.setLength(field
->pack_length());
4958 case MYSQL_TYPE_NEWDATE
:
4959 col
.setType(NDBCOL::Date
);
4962 case MYSQL_TYPE_TIME
:
4963 col
.setType(NDBCOL::Time
);
4966 case MYSQL_TYPE_YEAR
:
4967 col
.setType(NDBCOL::Year
);
4970 case MYSQL_TYPE_TIMESTAMP
:
4971 col
.setType(NDBCOL::Timestamp
);
4975 case MYSQL_TYPE_STRING
:
4976 if (field
->pack_length() == 0)
4978 col
.setType(NDBCOL::Bit
);
4981 else if ((field
->flags
& BINARY_FLAG
) && cs
== &my_charset_bin
)
4983 col
.setType(NDBCOL::Binary
);
4984 col
.setLength(field
->pack_length());
4988 col
.setType(NDBCOL::Char
);
4990 col
.setLength(field
->pack_length());
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
);
5002 col
.setType(NDBCOL::Varchar
);
5006 else if (f
->length_bytes
== 2)
5008 if ((field
->flags
& BINARY_FLAG
) && cs
== &my_charset_bin
)
5009 col
.setType(NDBCOL::Longvarbinary
);
5011 col
.setType(NDBCOL::Longvarchar
);
5017 return HA_ERR_UNSUPPORTED
;
5019 col
.setLength(field
->field_length
);
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
);
5028 col
.setType(NDBCOL::Text
);
5031 col
.setInlineSize(256);
5034 col
.setStripeSize(0);
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
);
5042 col
.setType(NDBCOL::Text
);
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
;
5066 goto mysql_type_long_blob
;
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
);
5074 col
.setType(NDBCOL::Text
);
5077 col
.setInlineSize(256);
5078 col
.setPartSize(4000);
5079 col
.setStripeSize(8);
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
);
5086 col
.setType(NDBCOL::Text
);
5089 col
.setInlineSize(256);
5090 col
.setPartSize(8000);
5091 col
.setStripeSize(4);
5094 case MYSQL_TYPE_ENUM
:
5095 col
.setType(NDBCOL::Char
);
5096 col
.setLength(field
->pack_length());
5098 case MYSQL_TYPE_SET
:
5099 col
.setType(NDBCOL::Char
);
5100 col
.setLength(field
->pack_length());
5102 case MYSQL_TYPE_BIT
:
5104 int no_of_bits
= field
->field_length
;
5105 col
.setType(NDBCOL::Bit
);
5109 col
.setLength(no_of_bits
);
5112 case MYSQL_TYPE_NULL
:
5113 goto mysql_type_unsupported
;
5114 mysql_type_unsupported
:
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
)
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
);
5134 col
.setAutoIncrement(FALSE
);
5139 Create a table in NDB Cluster
5142 int ha_ndbcluster::create(const char *name
,
5144 HA_CREATE_INFO
*create_info
)
5146 THD
*thd
= current_thd
;
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);
5164 if ((my_errno
= check_ndb_connection()))
5165 DBUG_RETURN(my_errno
);
5167 Ndb
*ndb
= get_ndb();
5168 NDBDICT
*dict
= ndb
->getDictionary();
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
;
5180 DBUG_PRINT("info", ("Dropping and re-creating table for TRUNCATE"));
5181 if ((my_errno
= delete_table(name
)))
5182 DBUG_RETURN(my_errno
);
5185 if (create_from_engine
)
5188 Table already exists in NDB and frm file has been created by
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
))
5231 if (packfrm(data
, length
, &pack_data
, &pack_length
))
5233 my_free((char*)data
, MYF(0));
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
);
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 "
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
);
5282 case ROW_TYPE_DYNAMIC
:
5283 /* fall through, treat as default */
5285 /* fall through, treat as default */
5286 case ROW_TYPE_DEFAULT
:
5287 tab
.setForceVarPart(TRUE
);
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
);
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
);
5321 case ROW_TYPE_DYNAMIC
:
5323 Future: make columns dynamic in this case
5329 if (tab
.addColumn(col
))
5331 DBUG_RETURN(my_errno
= errno
);
5333 if (col
.getPrimaryKey())
5334 pk_length
+= (field
->pack_length() + 3) / 4;
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
);
5357 col
.setNullable(FALSE
);
5358 col
.setPrimaryKey(TRUE
);
5359 col
.setAutoIncrement(TRUE
);
5360 if (tab
.addColumn(col
))
5362 DBUG_RETURN(my_errno
= errno
);
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
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
5419 m_table
= ndbtab_g
.get_table();
5420 // TODO check also that we have the same frm...
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
);
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
);
5438 my_errno
= write_ndb_file(name
);
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
:
5451 continue; // retry indefinitly
5459 DBUG_RETURN(my_errno
);
5462 #ifdef HAVE_NDB_BINLOG
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
);
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 */
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)
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());
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(),
5534 SOT_TRUNCATE_TABLE
: SOT_CREATE_TABLE
,
5539 #endif /* HAVE_NDB_BINLOG */
5542 DBUG_RETURN(my_errno
);
5545 int ha_ndbcluster::create_handler_files(const char *file
,
5546 const char *old_name
,
5548 HA_CREATE_INFO
*create_info
)
5552 uchar
*data
= NULL
, *pack_data
= NULL
;
5553 size_t length
, pack_length
;
5556 DBUG_ENTER("create_handler_files");
5558 if (action_flag
!= CHF_INDEX_FLAG
)
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
5571 DBUG_ASSERT(m_table
!= 0);
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
));
5591 DBUG_PRINT("info", ("Table %s has changed, altering frm in ndb",
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
5613 int ha_ndbcluster::create_index(const char *name
, KEY
*key_info
,
5614 NDB_INDEX_TYPE idx_type
, uint idx_no
)
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
));
5630 case PRIMARY_KEY_INDEX
:
5631 // Do nothing, already created
5633 case PRIMARY_KEY_ORDERED_INDEX
:
5634 error
= create_ordered_index(name
, key_info
);
5636 case UNIQUE_ORDERED_INDEX
:
5637 if (!(error
= create_ordered_index(name
, key_info
)))
5638 error
= create_unique_index(unique_name
, key_info
);
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
);
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
;
5661 error
= create_ordered_index(name
, key_info
);
5671 int ha_ndbcluster::create_ordered_index(const char *name
,
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
,
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.
5691 Only temporary ordered indexes supported
5694 int ha_ndbcluster::create_ndb_index(const char *name
,
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
);
5708 ndb_index
.setType(NdbDictionary::Index::UniqueHashIndex
);
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());
5734 DBUG_PRINT("info", ("Created index %s", name
));
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
)
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
];
5773 // Create index in ndb
5774 if((error
= create_index(key_info
[idx
].name
, key
, idx_type
, idx
)))
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
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
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
;
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
);
5813 Really drop all indexes marked for deletion
5815 int ha_ndbcluster::final_drop_index(TABLE
*table_arg
)
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
5836 Rename a table in NDB Cluster.
5839 int ha_ndbcluster::rename_table(const char *from
, const char *to
)
5842 char old_dbname
[FN_HEADLEN
];
5843 char new_dbname
[FN_HEADLEN
];
5844 char new_tabname
[FN_HEADLEN
];
5845 const NDBTAB
*orig_tab
;
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
);
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
);
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);
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
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
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
));
5909 ERR_RETURN(ndb_error
);
5913 if ((result
= handler::rename_table(from
, to
)))
5915 // ToDo in 4.1 should rollback alter table...
5916 #ifdef HAVE_NDB_BINLOG
5919 /* ndb_share reference temporary free */
5920 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
5921 share
->key
, share
->use_count
));
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
,
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());
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
,
5976 m_dbname
, new_tabname
, 1);
5979 // If we are moving tables between databases, we need to recreate
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
))
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()));
5999 ndb
->setDatabaseName(m_dbname
);
6000 dict
->dropIndexGlobal(*index
);
6006 /* ndb_share reference temporary free */
6007 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6008 share
->key
, share
->use_count
));
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
,
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
);
6049 DBUG_PRINT("NDB_SHARE", ("%s temporary use_count: %u",
6050 share
->key
, share
->use_count
));
6054 /* Drop the table from NDB */
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"));
6068 switch (dict
->getNdbError().status
)
6070 case NdbError::TemporaryError
:
6072 goto retry_temporary_error1
; // retry indefinitly
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
);
6085 ndb
->setDatabaseName(db
);
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"));
6101 switch (dict
->getNdbError().status
)
6103 case NdbError::TemporaryError
:
6105 goto retry_temporary_error2
; // retry indefinitly
6108 if (dict
->getNdbError().code
== NDB_INVALID_SCHEMA_OBJECT
)
6110 ndbtab_g
.invalidate();
6117 set_ndb_err(thd
, dict
->getNdbError());
6118 res
= ndb_to_mysql_error(&dict
->getNdbError());
6119 DBUG_PRINT("info", ("error(2) %u", res
));
6126 #ifdef HAVE_NDB_BINLOG
6127 /* the drop table failed for some reason, drop the share anyways */
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
);
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");
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
);
6209 int ha_ndbcluster::delete_table(const char *name
)
6211 DBUG_ENTER("ha_ndbcluster::delete_table");
6212 DBUG_PRINT("enter", ("name: %s", 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
);
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
)
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
;
6258 (remaining
< thd
->variables
.ndb_autoincrement_prefetch_sz
) ?
6259 thd
->variables
.ndb_autoincrement_prefetch_sz
6261 cache_size
= ((remaining
< m_autoincrement_prefetch
) ?
6264 uint retries
= NDB_AUTO_INCREMENT_RETRIES
;
6265 int retry_sleep
= 30; /* 30 milliseconds, transaction */
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
))
6274 ndb
->getNdbError().status
== NdbError::TemporaryError
)
6276 my_sleep(retry_sleep
);
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;
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;
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 | \
6306 HA_AUTO_PART_KEY | \
6307 HA_NO_PREFIX_CHAR_KEYS | \
6308 HA_NEED_READ_RANGE_BUFFER | \
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 | \
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
),
6324 m_table_flags(HA_NDBCLUSTER_TABLE_FLAGS
),
6327 m_use_partition_function(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
),
6342 m_skip_auto_increment(TRUE
),
6346 m_blobs_buffer_size(0),
6347 m_dupkey((uint
) -1),
6348 m_ha_not_exact_count(FALSE
),
6350 m_autoincrement_prefetch((ha_rows
) NDB_DEFAULT_AUTO_PREFETCH
),
6351 m_transaction_on(TRUE
),
6353 m_multi_cursor(NULL
)
6357 DBUG_ENTER("ha_ndbcluster");
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
]);
6372 int ha_ndbcluster::ha_initialise()
6374 DBUG_ENTER("ha_ndbcluster::ha_initialise");
6375 if (check_ndb_in_thd(current_thd
))
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");
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
));
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"));
6425 Open a table for further use.
6427 - fetch metadata for this table from NDB
6428 - check that table exists
6433 < 0 Table has changed
6436 int ha_ndbcluster::open(const char *name
, int mode
, uint test_if_locked
)
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
)))
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);
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
);
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());
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
;
6500 res
= info(HA_STATUS_CONST
);
6505 free_share(&m_share
);
6507 release_metadata(current_thd
, get_ndb());
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
);
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
);
6557 release_metadata(thd
, ndb
);
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()
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
;
6579 if (thd_ndb
->ndb
->init(max_transactions
) != 0)
6581 ERR_PRINT(thd_ndb
->ndb
->getNdbError());
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
6591 DBUG_RETURN(thd_ndb
);
6595 void ha_ndbcluster::release_thd_ndb(Thd_ndb
* thd_ndb
)
6597 DBUG_ENTER("release_thd_ndb");
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
);
6615 if (!(thd_ndb
= ha_ndbcluster::seize_thd_ndb()))
6617 set_thd_ndb(thd
, thd_ndb
);
6619 return thd_ndb
->ndb
;
6624 int ha_ndbcluster::check_ndb_connection(THD
* thd
)
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());
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");
6645 ha_ndbcluster::release_thd_ndb(thd_ndb
);
6646 set_thd_ndb(thd
, NULL
); // not strictly required but does not hurt either
6653 Try to discover one table from NDB.
6656 int ndbcluster_discover(handlerton
*hton
, THD
* thd
, const char *db
,
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
);
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"));
6697 Ndb_table_guard
ndbtab_g(dict
, name
);
6698 const NDBTAB
*tab
= ndbtab_g
.get_table();
6701 const NdbError err
= dict
->getNdbError();
6702 if (err
.code
== 709 || err
.code
== 723)
6705 DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error
.code
));
6711 DBUG_PRINT("info", ("ndb_error.code: %u", ndb_error
.code
));
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."));
6725 if (unpackfrm(&data
, &len
, (uchar
*) tab
->getFrmData()))
6727 DBUG_PRINT("error", ("Could not unpack table"));
6738 /* ndb_share reference temporary free */
6739 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6740 share
->key
, share
->use_count
));
6746 my_free((char*)data
, MYF(MY_ALLOW_ZERO_PTR
));
6749 /* ndb_share reference temporary free */
6750 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
6751 share
->key
, share
->use_count
));
6756 ERR_RETURN(ndb_error
);
6762 Check if a table exists in NDB.
6765 int ndbcluster_table_exists_in_engine(handlerton
*hton
, THD
* thd
,
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
))
6784 if (my_strcasecmp(system_charset_info
, elmt
.name
, name
))
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
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
];
6814 NdbDictionary::Dictionary::List list
;
6817 List
<char> drop_list
;
6819 ha_ndbcluster::set_dbname(path
, (char *)&dbname
);
6820 DBUG_PRINT("enter", ("db: %s", dbname
));
6822 if (!(ndb
= check_ndb_in_thd(thd
)))
6825 // List tables in NDB
6826 NDBDICT
*dict
= ndb
->getDictionary();
6827 if (dict
->listObjects(list
,
6828 NdbDictionary::Object::UserTable
) != 0)
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
))
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
));
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
);
6883 ndbcluster_drop_database_impl(path
);
6884 #ifdef HAVE_NDB_BINLOG
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);
6895 int ndb_create_table_from_engine(THD
*thd
, const char *db
,
6896 const char *table_name
)
6898 LEX
*old_lex
= thd
->lex
, newlex
;
6900 newlex
.current_select
= NULL
;
6902 int res
= ha_create_table_from_engine(thd
, db
, table_name
);
6908 find all tables in ndb and discover those needed
6910 int ndbcluster_find_all_files(THD
*thd
)
6913 char key
[FN_REFLEN
+ 1];
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
);
6927 NdbDictionary::Dictionary::List list
;
6928 if (dict
->listObjects(list
, NdbDictionary::Object::UserTable
) != 0)
6929 ERR_RETURN(dict
->getNdbError());
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
));
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
);
6952 ndb
->setDatabaseName(elmt
.database
);
6953 Ndb_table_guard
ndbtab_g(dict
, elmt
.name
);
6954 const NDBTAB
*ndbtab
= ndbtab_g
.get_table();
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
);
6966 if (ndbtab
->getFrmLength() == 0)
6969 /* check if database exists */
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 */
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
;
6983 if (readfrm(key
, &data
, &length
) ||
6984 packfrm(data
, length
, &pack_data
, &pack_length
))
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
);
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
)
7002 sql_print_information("NDB: mismatch in frm for %s.%s, discovering...",
7003 elmt
.database
, elmt
.name
);
7007 /* ndb_share reference temporary free */
7008 DBUG_PRINT("NDB_SHARE", ("%s temporary free use_count: %u",
7009 share
->key
, share
->use_count
));
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
);
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
7028 /* set up replication for this table */
7029 ndbcluster_create_binlog_setup(ndb
, key
, end
-key
,
7030 elmt
.database
, elmt
.name
,
7034 pthread_mutex_unlock(&LOCK_open
);
7037 while (unhandled
&& retries
);
7039 DBUG_RETURN(-(skipped
+ unhandled
));
7042 int ndbcluster_find_files(handlerton
*hton
, THD
*thd
,
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
7052 char name
[FN_REFLEN
+ 1];
7053 HASH ndb_tables
, ok_tables
;
7056 if (!(ndb
= check_ndb_in_thd(thd
)))
7057 DBUG_RETURN(HA_ERR_NO_CONNECTION
);
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"));
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
);
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
));
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
))
7097 // Apply wildcard to list of tables in NDB
7100 if (lower_case_table_names
)
7102 if (wild_case_compare(files_charset_info
, elmt
.name
, wild
))
7105 else if (wild_compare(elmt
.name
,wild
,0))
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",
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
);
7138 pthread_mutex_unlock(&LOCK_open
);
7140 DBUG_PRINT("info", ("%s existed in NDB _and_ on disk ", file_name
->str
));
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
7154 // Ignore this ndb table
7155 uchar
*record
= hash_search(&ndb_tables
, (uchar
*) file_name
->str
,
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
);
7168 // File existed in NDB and as frm file, put in ok_tables list
7169 my_hash_insert(&ok_tables
, (uchar
*) file_name
->str
);
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
));
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
);
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
);
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
)
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 */
7246 pthread_mutex_lock(&LOCK_open
);
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
))
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
));
7279 files
->push_back(file_name
);
7282 } // extra bracket to avoid gcc 2.95.3 warning
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
);
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
);
7309 extern int ndb_dictionary_is_mysqld
;
7310 extern pthread_mutex_t LOCK_plugin
;
7312 static int ndbcluster_init(void *p
)
7315 DBUG_ENTER("ndbcluster_init");
7317 if (ndbcluster_inited
)
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();
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
;
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)
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);
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
;
7407 ("NDBCLUSTER storage engine not started, "
7408 "will connect using %s",
7409 g_ndb_cluster_connection
->
7410 get_connectstring(buf
,sizeof(buf
))));
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
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;
7463 ndbcluster_init_error
:
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
7475 static int ndbcluster_end(handlerton
*hton
, ha_panic_function type
)
7477 DBUG_ENTER("ndbcluster_end");
7479 if (!ndbcluster_inited
)
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
)
7499 (NDB_SHARE
*) hash_element(&ndbcluster_open_tables
, 0);
7501 fprintf(stderr
, "NDB: table share %s with use_count %d not freed\n",
7502 share
->key
, share
->use_count
);
7504 ndbcluster_real_free_share(&share
);
7506 pthread_mutex_unlock(&ndbcluster_mutex
);
7509 hash_free(&ndbcluster_open_tables
);
7514 Ndb::Free_list_usage tmp
;
7516 while (g_ndb
->get_free_list_usage(&tmp
))
7518 uint leaked
= (uint
) tmp
.m_created
- tmp
.m_free
;
7520 fprintf(stderr
, "NDB: Found %u %s%s that %s not been released\n",
7522 (leaked
== 1)?"":"'s",
7523 (leaked
== 1)?"has":"have");
7529 delete g_ndb_cluster_connection
;
7530 g_ndb_cluster_connection
= NULL
;
7532 // cleanup ndb interface
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
);
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
);
7550 handler::print_error(error
, errflag
);
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");
7564 const char *tab_name
= (error_op
) ? error_op
->getTableName() : "";
7565 share
.db
.str
= (char*) "";
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));
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];
7584 /* Scan name from the end */
7585 ptr
= strend(path_name
)-1;
7586 while (ptr
>= path_name
&& *ptr
!= '\\' && *ptr
!= '/') {
7591 while (ptr
>= path_name
&& *ptr
!= '\\' && *ptr
!= '/') {
7594 uint name_len
= end
- ptr
;
7595 memcpy(tmp_name
, ptr
+ 1, name_len
);
7596 tmp_name
[name_len
]= '\0';
7598 /* Put to lower case */
7602 while (*ptr
!= '\0') {
7603 *ptr
= tolower(*ptr
);
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.
7624 ha_ndbcluster::set_tabname(const char *path_name
, char * tabname
)
7626 char *end
, *ptr
, *tmp_name
;
7627 char tmp_buff
[FN_REFLEN
+ 1];
7630 /* Scan name from the end */
7631 end
= strend(path_name
)-1;
7633 while (ptr
>= path_name
&& *ptr
!= '\\' && *ptr
!= '/') {
7636 uint name_len
= end
- ptr
;
7637 memcpy(tmp_name
, ptr
+ 1, end
- ptr
);
7638 tmp_name
[name_len
]= '\0';
7640 /* Put to lower case */
7643 while (*ptr
!= '\0') {
7644 *ptr
= tolower(*ptr
);
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
);
7662 ha_ndbcluster::records_in_range(uint inx
, key_range
*min_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
)))
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
;
7691 NdbTransaction
* trans
=NULL
;
7692 NdbIndexScanOperation
* op
=NULL
;
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
));
7708 Ndb_statistics stat
;
7709 if ((res
=ndb_get_table_statistics(this, TRUE
, ndb
, m_table
, &stat
)))
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
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)
7738 // Decide if db should be contacted
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
++;
7752 if (trans
!= m_active_trans
&& rows
== 0)
7754 if (trans
!= m_active_trans
&& trans
!= NULL
)
7755 ndb
->closeTransaction(trans
);
7757 DBUG_RETURN(HA_POS_ERROR
);
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
;
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
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
7810 const char* ha_ndbcluster::index_type(uint key_number
)
7812 switch (get_index_type(key_number
)) {
7814 case UNIQUE_ORDERED_INDEX
:
7815 case PRIMARY_KEY_ORDERED_INDEX
:
7818 case PRIMARY_KEY_INDEX
:
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];
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
,
7846 pthread_mutex_unlock(&ndbcluster_mutex
);
7847 DBUG_PRINT("info", ("Table %s not found in ndbcluster_open_tables", name
));
7850 /* ndb_share reference temporary, free below */
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
;
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
));
7875 DBUG_PRINT("info", ("Get commit_count from NDB"));
7877 if (!(ndb
= check_ndb_in_thd(thd
)))
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
));
7900 pthread_mutex_lock(&share
->mutex
);
7901 if (share
->commit_count_lock
== lock
)
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
;
7913 DBUG_PRINT("info", ("Discarding commit_count, comit_count_lock changed"));
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
));
7926 Check if a cached query can be used.
7928 This is done by comparing the supplied engine_data to commit_count of
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.
7947 TRUE Yes, use the query from cache
7949 FALSE No, don't use the cached query, and if engine_data
7950 has changed, all queries for this table should be invalidated
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;
7964 char buff
[22], buff2
[22];
7966 DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
7967 DBUG_PRINT("enter", ("dbname: %s, tabname: %s, is_autocommit: %d",
7968 dbname
, tabname
, is_autocommit
));
7972 DBUG_PRINT("exit", ("No, don't use cache in transaction"));
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"));
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"));
7990 else if (*engine_data
!= commit_count
)
7992 *engine_data
= commit_count
; /* invalidate */
7993 DBUG_PRINT("exit", ("No, commit_count has changed"));
7997 DBUG_PRINT("exit", ("OK to use cache, engine_data: %s",
7998 llstr(*engine_data
, buff
)));
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
8017 @param[out] engine_data commit_count for this table
8020 TRUE Yes, it's ok to cahce this query
8022 FALSE No, don't cach the query
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
;
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
));
8042 DBUG_PRINT("exit", ("Can't register table during transaction"));
8046 if (ndb_get_commitcount(thd
, m_dbname
, m_tabname
, &commit_count
))
8049 DBUG_PRINT("exit", ("Error, could not get commitcount"));
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
;
8078 static void print_share(const char* where
, NDB_SHARE
* share
)
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
);
8085 " - key: %s, key_length: %d\n",
8086 share
->key
, share
->key_length
);
8088 #ifdef HAVE_NDB_BINLOG
8091 " - share->table: %p %s.%s\n",
8092 share
->table
, share
->table
->s
->db
.str
,
8093 share
->table
->s
->table_name
.str
);
8098 static void print_ndbcluster_open_tables()
8101 fprintf(DBUG_FILE
, ">ndbcluster_open_tables\n");
8102 for (uint i
= 0; i
< ndbcluster_open_tables
.records
; i
++)
8104 (NDB_SHARE
*)hash_element(&ndbcluster_open_tables
, i
));
8105 fprintf(DBUG_FILE
, "<ndbcluster_open_tables\n");
8112 #define dbug_print_open_tables() \
8113 DBUG_EXECUTE("info", \
8114 print_ndbcluster_open_tables(););
8116 #define dbug_print_share(t, s) \
8118 DBUG_EXECUTE("info", \
8119 print_share((t), (s));); \
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 */
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",
8165 share
->connect_count
,
8166 g_ndb_cluster_connection
->get_connect_count());
8167 ndbcluster_real_free_share(&share
);
8172 share still exists, if share has not been dropped by server
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
));
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",
8191 share
->connect_count
,
8192 g_ndb_cluster_connection
->get_connect_count());
8193 ndbcluster_real_free_share(&share
);
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
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
;
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
);
8239 Rename share is used during rename table.
8241 static int rename_share(NDB_SHARE
*share
, const char *new_key
)
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",
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",
8281 dbug_print_open_tables();
8282 pthread_mutex_unlock(&ndbcluster_mutex
);
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
);
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
);
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
);
8321 dbug_print_open_tables();
8322 dbug_print_share("ndbcluster_get_share:", share
);
8323 pthread_mutex_unlock(&ndbcluster_mutex
);
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
,
8348 uint length
= (uint
) strlen(key
);
8349 DBUG_ENTER("ndbcluster_get_share");
8350 DBUG_PRINT("enter", ("key: '%s'", key
));
8353 pthread_mutex_lock(&ndbcluster_mutex
);
8354 if (!(share
= (NDB_SHARE
*) hash_search(&ndbcluster_open_tables
,
8358 if (!create_if_not_exists
)
8360 DBUG_PRINT("error", ("get_share: %s does not exist", key
));
8362 pthread_mutex_unlock(&ndbcluster_mutex
);
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
;
8384 pthread_mutex_unlock(&ndbcluster_mutex
);
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
;
8402 pthread_mutex_unlock(&ndbcluster_mutex
);
8406 *root_ptr
= old_root
;
8410 DBUG_PRINT("error", ("get_share: failed to alloc share"));
8412 pthread_mutex_unlock(&ndbcluster_mutex
);
8413 my_error(ER_OUTOFMEMORY
, MYF(0), static_cast<int>(sizeof(*share
)));
8419 dbug_print_open_tables();
8420 dbug_print_share("ndbcluster_get_share:", share
);
8422 pthread_mutex_unlock(&ndbcluster_mutex
);
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
);
8444 bzero((uchar
*)(*share
)->table_share
, sizeof(*(*share
)->table_share
));
8445 bzero((uchar
*)(*share
)->table
, sizeof(*(*share
)->table
));
8446 (*share
)->table_share
= 0;
8451 free_root(&(*share
)->mem_root
, MYF(0));
8452 my_free((uchar
*) *share
, MYF(0));
8455 dbug_print_open_tables();
8460 void ndbcluster_free_share(NDB_SHARE
**share
, bool 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
);
8472 dbug_print_open_tables();
8473 dbug_print_share("ndbcluster_free_share:", *share
);
8476 pthread_mutex_unlock(&ndbcluster_mutex
);
8482 ndb_get_table_statistics(ha_ndbcluster
* file
, bool report_error
, Ndb
* ndb
, const NDBTAB
*ndbtab
,
8483 struct Ndb_statistics
* ndbstat
)
8485 NdbTransaction
* pTrans
;
8489 int retry_sleep
= 30; /* 30 milliseconds, transaction */
8491 char buff
[22], buff2
[22], buff3
[22], buff4
[22];
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
;
8504 Uint64 sum_commits
= 0;
8505 Uint64 sum_row_size
= 0;
8507 NdbScanOperation
*pOp
;
8510 if ((pTrans
= ndb
->startTransaction()) == NULL
)
8512 error
= ndb
->getNdbError();
8516 if ((pOp
= pTrans
->getNdbScanOperation(ndbtab
)) == NULL
)
8518 error
= pTrans
->getNdbError();
8522 if (pOp
->readTuples(NdbOperation::LM_CommittedRead
))
8524 error
= pOp
->getNdbError();
8528 if (pOp
->interpret_exit_last_row() == -1)
8530 error
= pOp
->getNdbError();
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
,
8539 pOp
->getValue(NdbDictionary::Column::FRAGMENT_VARSIZED_MEMORY
,
8542 if (pTrans
->execute(NdbTransaction::NoCommit
,
8543 NdbOperation::AbortOnError
,
8546 error
= pTrans
->getNdbError();
8550 while ((check
= pOp
->nextResult(TRUE
, TRUE
)) == 0)
8553 sum_commits
+= commits
;
8554 if (sum_row_size
< size
)
8556 sum_mem
+= fixed_mem
+ var_mem
;
8562 error
= pOp
->getNdbError();
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
),
8589 reterr
= file
->ndb_err(pTrans
);
8593 const NdbError
& tmp
= error
;
8595 reterr
= ndb_to_mysql_error(&tmp
);
8603 ndb
->closeTransaction(pTrans
);
8606 if (error
.status
== NdbError::TemporaryError
&& retries
--)
8608 my_sleep(retry_sleep
);
8611 set_ndb_err(current_thd
, error
);
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
)
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
8640 my_close(file
,MYF(0));
8646 ha_ndbcluster::release_completed_operations(NdbTransaction
*trans
,
8649 if (trans
->hasBlobOperation())
8651 /* We are reading/writing BLOB fields,
8652 releasing operation records is unsafe
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
8666 trans
->releaseCompletedOperations();
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
;
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
))
8694 ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE
**found_range_p
,
8695 KEY_MULTI_RANGE
*ranges
,
8698 HANDLER_BUFFER
*buffer
)
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
;
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
,
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)
8744 * range 3 range (3,5) NOTE result rows will be intermixed
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
;
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
,
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
8785 multi_range_curr
->range_flag
|= SKIP_RANGE
;
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
))
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
)))
8806 ERR_RETURN(op
? op
->getNdbError() : m_active_trans
->getNdbError());
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
)))
8816 // else fall through
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
))
8826 ERR_RETURN(op
? op
->getNdbError() : m_active_trans
->getNdbError());
8829 case ORDERED_INDEX
: {
8831 multi_range_curr
->range_flag
&= ~(uint
)UNIQUE_RANGE
;
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
;
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
)))
8868 case UNDEFINED_INDEX
:
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
;
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());
8906 #define DBUG_MULTI_RANGE(x) DBUG_PRINT("info", ("read_multi_range_next: case %d\n", x));
8908 #define DBUG_MULTI_RANGE(x)
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
));
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
)
8930 if (multi_range_curr
->range_flag
& UNIQUE_RANGE
)
8932 if (op
->getNdbError().code
== 0)
8934 DBUG_MULTI_RANGE(13);
8938 op
= m_active_trans
->getNextCompletedOperation(op
);
8939 m_multi_range_result_ptr
+= reclength
;
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();
8953 DBUG_MULTI_RANGE(14);
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);
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
8973 else if (range_no
> (int)current_range_no
)
8975 DBUG_MULTI_RANGE(5);
8976 // wait with current row
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);
8990 multi_range_curr
--; // Will be increased in for-loop
8994 else /* m_multi_cursor == 0 */
8996 DBUG_MULTI_RANGE(7);
8998 * Corresponds to range 5 in example in read_multi_range_first
9004 DBUG_ASSERT(FALSE
); // Should only get here via goto's
9008 m_multi_cursor
->close(FALSE
, TRUE
);
9009 m_active_cursor
= m_multi_cursor
= 0;
9010 DBUG_MULTI_RANGE(8);
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
,
9033 multi_range_end
- multi_range_curr
,
9035 multi_range_buffer
));
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]);
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]);
9061 m_current_multi_operation
= m_active_trans
->getNextCompletedOperation(op
);
9062 m_multi_range_result_ptr
+= reclength
;
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
++)
9080 DBUG_ASSERT(curr
!= 0);
9081 NdbValue
* val
= m_value
+ curr
->getColumn()->getColumnNo();
9082 DBUG_ASSERT(val
->ptr
);
9092 @param[in] comment table comment defined by user
9095 table comment + additional
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 */
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
);
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());
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
;
9146 uint share_list_size
= 0;
9147 NDB_SHARE
**share_list
= NULL
;
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_ */
9158 my_errno
= HA_ERR_OUT_OF_MEM
;
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
;
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
,
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
);
9238 Get all table definitions from the storage node
9240 ndbcluster_find_all_files(thd
);
9243 set_timespec(abstime
, 0);
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
,
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
));
9259 #ifdef HAVE_NDB_BINLOG
9261 Check that the ndb_apply_status_share and ndb_schema_share
9263 If not try to create it
9265 if (!ndb_binlog_tables_inited
)
9266 ndbcluster_setup_binlog_table_shares(thd
);
9269 if (ndb_cache_check_time
== 0)
9271 /* Wake up in 1 second to check if value has changed */
9272 set_timespec(abstime
, 1);
9276 /* Lock mutex and fill list with pointers to all open tables */
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))
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))
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
));
9333 #endif /* HAVE_NDB_BINLOG */
9334 DBUG_PRINT("ndb_util_thread",
9335 ("Fetching commit count for: %s", share
->key
));
9337 struct Ndb_statistics stat
;
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
))
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)
9355 char buff
[22], buff2
[22];
9358 ("Table: %s commit_count: %s rows: %s",
9360 llstr(stat
.commit_count
, buff
),
9361 llstr(stat
.row_count
, buff2
)));
9365 DBUG_PRINT("ndb_util_thread",
9366 ("Error: Could not get commit count for table %s",
9368 stat
.commit_count
= 0;
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
));
9383 /* Calculate new time to wake up */
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;
9394 msecs
= msecs
% 1000;
9397 abstime
.tv_sec
+= secs
;
9398 abstime
.tv_nsec
+= msecs
* 1000000;
9399 if (abstime
.tv_nsec
>= 1000000000) {
9401 abstime
.tv_nsec
-= 1000000000;
9405 pthread_mutex_lock(&LOCK_ndb_util_thread
);
9407 ndb_util_thread_end
:
9409 ndb_util_thread_fail
:
9411 delete [] share_list
;
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()
9424 return NULL
; // Avoid compiler warnings
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".
9442 NULL The condition was supported and will be evaluated for each
9443 row found during the scan
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)
9450 ha_ndbcluster::cond_push(const COND
*cond
)
9452 DBUG_ENTER("cond_push");
9454 m_cond
= new ha_ndbcluster_cond
;
9457 my_errno
= HA_ERR_OUT_OF_MEM
;
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.
9468 ha_ndbcluster::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();
9484 ndb
->setDatabaseName(m_dbname
);
9485 const NDBTAB
*ndbtab
= m_table
;
9486 DBUG_ASSERT(ndbtab
!= NULL
);
9487 if (!ndbtab
->getTablespace(&id
))
9492 NdbDictionary::Tablespace ts
= ndbdict
->getTablespace(id
);
9493 ndberr
= ndbdict
->getNdbError();
9494 if(ndberr
.classification
!= NdbError::NoError
)
9496 DBUG_PRINT("info", ("Found tablespace '%s'", ts
.getName()));
9499 strxnmov(name
, name_len
, ts
.getName(), NullS
);
9503 return (my_strdup(ts
.getName(), MYF(0)));
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");
9511 push_warning_printf(thd
, MYSQL_ERROR::WARN_LEVEL_ERROR
,
9512 ER_GET_ERRMSG
, ER(ER_GET_ERRMSG
),
9513 ndberr
.code
, ndberr
.message
, "NDB");
9518 Implements the SHOW NDB STATUS command.
9521 ndbcluster_show_status(handlerton
*hton
, THD
* thd
, stat_print_fn
*stat_print
,
9522 enum ha_stat_type stat_type
)
9526 DBUG_ENTER("ndbcluster_show_status");
9528 if (stat_type
!= HA_ENGINE_STATUS
)
9533 update_status_variables(g_ndb_cluster_connection
);
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
,
9545 ndb_number_of_data_nodes
,
9546 ndb_number_of_ready_data_nodes
,
9548 if (stat_print(thd
, ndbcluster_hton_name
, ndbcluster_hton_name_length
,
9549 STRING_WITH_LEN("connection"), buf
, buflen
))
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
;
9557 while (ndb
->get_free_list_usage(&tmp
))
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
))
9568 #ifdef HAVE_NDB_BINLOG
9569 ndbcluster_show_status_binlog(thd
, stat_print
, stat_type
);
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;
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;
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;
9595 return ((max_rows
*acc_row_size
)/acc_fragment_size
+1
9596 +1/*correct rounding*/)/2;
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
)
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
;
9622 max_rows
= create_info
->max_rows
;
9623 min_rows
= create_info
->min_rows
;
9627 max_rows
= table_share
->max_rows
;
9628 min_rows
= table_share
->min_rows
;
9630 uint reported_frags
;
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
9648 set_auto_partitions()
9649 part_info Partition info struct to set-up
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
)
9669 part_info
->linear_hash_ind
= FALSE
;
9672 part_info
->linear_hash_ind
= TRUE
;
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
),
9686 bool unsigned_flag
= part_info
->part_expr
->unsigned_flag
;
9687 DBUG_ENTER("set_range_data");
9691 mem_alloc_error(part_info
->no_parts
*sizeof(int32
));
9694 for (i
= 0; i
< part_info
->no_parts
; i
++)
9696 longlong range_val
= part_info
->range_int_array
[i
];
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");
9708 range_val
= INT_MAX32
;
9710 range_data
[i
]= (int32
)range_val
;
9712 tab
->setRangeListData(range_data
, sizeof(int32
)*part_info
->no_parts
);
9714 my_free((char*)range_data
, MYF(0));
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));
9725 bool unsigned_flag
= part_info
->part_expr
->unsigned_flag
;
9726 DBUG_ENTER("set_list_data");
9730 mem_alloc_error(part_info
->no_list_values
*2*sizeof(int32
));
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
;
9738 list_val
-= 0x8000000000000000ULL
;
9739 if (list_val
< INT_MIN32
|| list_val
> INT_MAX32
)
9741 my_error(ER_LIMITED_PART_RANGE
, MYF(0), "NDB");
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
);
9751 my_free((char*)list_data
, MYF(0));
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
,
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
;
9779 uint tot_ts_name_len
;
9780 List_iterator
<partition_element
> part_it(part_info
->partitions
);
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
;
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
);
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.
9821 DBUG_PRINT("info", ("Generating partition func value field"));
9822 col
.setName("$PART_FUNC_VALUE");
9823 col
.setType(NdbDictionary::Column::Int
);
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
)))
9836 else if (part_info
->part_type
== LIST_PARTITION
)
9838 if ((error
= set_list_data((void*)tab
, part_info
)))
9844 tab
->setFragmentType(ftype
);
9850 part_elem
= part_it
++;
9851 if (!part_info
->is_sub_partitioned())
9853 ng
= part_elem
->nodegroup_id
;
9854 if (first
&& ng
== UNDEF_NODEGROUP
)
9856 ts_names
[fd_index
]= part_elem
->tablespace_name
;
9857 frag_data
[fd_index
++]= ng
;
9861 List_iterator
<partition_element
> sub_it(part_elem
->subpartitions
);
9865 part_elem
= sub_it
++;
9866 ng
= part_elem
->nodegroup_id
;
9867 if (first
&& ng
== UNDEF_NODEGROUP
)
9869 ts_names
[fd_index
]= part_elem
->tablespace_name
;
9870 frag_data
[fd_index
++]= ng
;
9871 } while (++j
< part_info
->no_subparts
);
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
)
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);
9895 bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO
*create_info
,
9898 DBUG_ENTER("ha_ndbcluster::check_if_incompatible_data");
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
);
9911 if (create_info
->tablespace
)
9912 create_info
->storage_media
= HA_SM_DISK
;
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
)
9941 if (field
->flags
& FIELD_IN_ADD_INDEX
)
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
);
9959 DBUG_PRINT("info", ("storage media is changed, old is DISK and tablespace=%s, new is MEM",
9961 DBUG_RETURN(COMPATIBLE_DATA_NO
);
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
);
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));
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
);
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
);
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
);
10037 int ndbcluster_alter_tablespace(handlerton
*hton
,
10038 THD
* thd
, st_alter_tablespace
*alter_info
)
10040 int is_tablespace
= 0;
10044 const char *errmsg
;
10046 DBUG_ENTER("ha_ndbcluster::alter_tablespace");
10049 ndb
= check_ndb_in_thd(thd
);
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
))
10068 if (set_up_datafile(alter_info
, &ndb_df
))
10072 errmsg
= "TABLESPACE";
10073 if (dict
->createTablespace(ndb_ts
, &objid
))
10075 DBUG_PRINT("error", ("createTablespace returned %d", error
));
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
));
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
))
10107 errmsg
= " CREATE DATAFILE";
10108 if (dict
->createDatafile(ndb_df
))
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
))
10130 DBUG_PRINT("error", ("No such datafile"));
10131 my_error(ER_ALTER_FILEGROUP_FAILED
, MYF(0), " NO SUCH FILE");
10137 DBUG_PRINT("error", ("Unsupported alter tablespace: %d",
10138 alter_info
->ts_alter_tablespace_type
));
10139 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED
);
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
))
10161 errmsg
= "LOGFILE GROUP";
10162 if (dict
->createLogfileGroup(ndb_lg
, &objid
))
10166 DBUG_PRINT("alter_info", ("Successfully created Logfile Group"));
10167 if (set_up_undofile(alter_info
, &ndb_uf
))
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
);
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
))
10201 errmsg
= "CREATE UNDOFILE";
10202 if (dict
->createUndofile(ndb_uf
))
10208 case (DROP_TABLESPACE
):
10210 error
= ER_DROP_FILEGROUP_FAILED
;
10211 errmsg
= "TABLESPACE";
10212 if (dict
->dropTablespace(dict
->getTablespace(alter_info
->tablespace_name
)))
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
)))
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
);
10239 DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED
);
10242 #ifdef HAVE_NDB_BINLOG
10244 ndbcluster_log_schema_op(thd
, 0,
10245 thd
->query(), thd
->query_length(),
10246 "", alter_info
->tablespace_name
,
10248 SOT_TABLESPACE
, 0, 0, 0);
10250 ndbcluster_log_schema_op(thd
, 0,
10251 thd
->query(), thd
->query_length(),
10252 "", alter_info
->logfile_group_name
,
10254 SOT_LOGFILE_GROUP
, 0, 0, 0);
10256 DBUG_RETURN(FALSE
);
10259 err
= dict
->getNdbError();
10261 set_ndb_err(thd
, err
);
10262 ndb_to_mysql_error(&err
);
10264 my_error(error
, MYF(0), errmsg
);
10269 bool ha_ndbcluster::get_no_parts(const char *name
, uint
*no_parts
)
10274 DBUG_ENTER("ha_ndbcluster::get_no_parts");
10281 if (check_ndb_connection())
10283 err
= HA_ERR_NO_CONNECTION
;
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));
10299 static int ndbcluster_fill_files_table(handlerton
*hton
,
10301 TABLE_LIST
*tables
,
10304 TABLE
* table
= tables
->table
;
10305 Ndb
*ndb
= check_ndb_in_thd(thd
);
10306 NdbDictionary::Dictionary
* dict
= ndb
->getDictionary();
10307 NdbDictionary::Dictionary::List dflist
;
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
;
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
)
10335 if (ndberr
.classification
== NdbError::UnknownResultError
)
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
)
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
);
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
;
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
)
10417 if (ndberr
.classification
== NdbError::UnknownResultError
)
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
)
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());
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
);
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
)
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
,
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());
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
);
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
,
10542 "Clustered, fault-tolerant tables",
10543 PLUGIN_LICENSE_GPL
,
10544 ndbcluster_init
, /* Plugin Init */
10545 NULL
, /* Plugin Deinit */
10547 ndb_status_variables_export
,/* status variables */
10548 NULL
, /* system variables */
10549 NULL
/* config options */
10551 mysql_declare_plugin_end
;