diff options
author | unknown <joreland@mysql.com> | 2005-01-09 05:03:33 +0100 |
---|---|---|
committer | unknown <joreland@mysql.com> | 2005-01-09 05:03:33 +0100 |
commit | 79192c23358c9604a8c854a1b626e61ecbd6b34c (patch) | |
tree | 2e9efb92a0336cd77303a613de2a714d86b22fea | |
parent | e7c19e9e00334b72e73d4070182712bd8bb0c7e7 (diff) | |
parent | 91a3e90baf0a515470622f7720fcea64745f70fa (diff) | |
download | mariadb-git-79192c23358c9604a8c854a1b626e61ecbd6b34c.tar.gz |
Merge joreland@bk-internal.mysql.com:/home/bk/mysql-5.0-ndb
into mysql.com:/home/jonas/src/mysql-5.0-ndb
35 files changed, 878 insertions, 414 deletions
diff --git a/client/completion_hash.cc b/client/completion_hash.cc index 536e7f9373a..7a3b363c93c 100644 --- a/client/completion_hash.cc +++ b/client/completion_hash.cc @@ -79,7 +79,8 @@ int completion_hash_update(HashTable *ht, char *arKey, uint nKeyLength, if (!memcmp(p->arKey, arKey, nKeyLength)) { entry *n; - n = (entry *) alloc_root(&ht->mem_root,sizeof(entry)); + if (!(n = (entry *) alloc_root(&ht->mem_root,sizeof(entry)))) + return FAILURE; n->pNext = p->pData; n->str = str; p->pData = n; diff --git a/client/mysql.cc b/client/mysql.cc index ace595f9cad..e605c2d7db4 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1502,7 +1502,10 @@ You can turn off this feature to get a quicker startup with -A\n\n"); if (!(field_names[i] = (char **) alloc_root(&hash_mem_root, sizeof(char *) * (num_fields*2+1)))) - break; + { + mysql_free_result(fields); + break; + } field_names[i][num_fields*2]= '\0'; j=0; while ((sql_field=mysql_fetch_field(fields))) @@ -2077,10 +2080,10 @@ print_table_data_html(MYSQL_RES *result) } while ((cur = mysql_fetch_row(result))) { + ulong *lengths=mysql_fetch_lengths(result); (void) tee_fputs("<TR>", PAGER); for (uint i=0; i < mysql_num_fields(result); i++) { - ulong *lengths=mysql_fetch_lengths(result); (void) tee_fputs("<TD>", PAGER); safe_put_field(cur[i],lengths[i]); (void) tee_fputs("</TD>", PAGER); @@ -2106,10 +2109,10 @@ print_table_data_xml(MYSQL_RES *result) fields = mysql_fetch_fields(result); while ((cur = mysql_fetch_row(result))) { + ulong *lengths=mysql_fetch_lengths(result); (void) tee_fputs("\n <row>\n", PAGER); for (uint i=0; i < mysql_num_fields(result); i++) { - ulong *lengths=mysql_fetch_lengths(result); tee_fprintf(PAGER, "\t<%s>", (fields[i].name ? (fields[i].name[0] ? fields[i].name : " ") : "NULL")); diff --git a/cmd-line-utils/libedit/makelist.sh b/cmd-line-utils/libedit/makelist.sh index fbce06fcc50..b2502d16ed1 100644 --- a/cmd-line-utils/libedit/makelist.sh +++ b/cmd-line-utils/libedit/makelist.sh @@ -145,7 +145,7 @@ case $FLAG in # -fh) cat $FILES | $AWK '/el_action_t/ { print $3 }' | \ - sort | tr '[a-z]' '[A-Z]' | $AWK ' + sort | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ | $AWK ' BEGIN { printf("/* Automatically generated file, do not edit */\n"); printf("#ifndef _h_fcns_c\n#define _h_fcns_c\n"); diff --git a/cmd-line-utils/libedit/parse.c b/cmd-line-utils/libedit/parse.c index b113353d464..d09b890c1ab 100644 --- a/cmd-line-utils/libedit/parse.c +++ b/cmd-line-utils/libedit/parse.c @@ -87,7 +87,8 @@ parse_line(EditLine *el, const char *line) int argc; Tokenizer *tok; - tok = tok_init(NULL); + if (!(tok = tok_init(NULL))) + return -1; tok_line(tok, line, &argc, &argv); argc = el_parse(el, argc, argv); tok_end(tok); diff --git a/mysql-test/r/ndb_index_ordered.result b/mysql-test/r/ndb_index_ordered.result index 1cf2a97a6b3..ccb202b25a8 100644 --- a/mysql-test/r/ndb_index_ordered.result +++ b/mysql-test/r/ndb_index_ordered.result @@ -419,3 +419,113 @@ SubscrID SbclID 3 NULL drop table test1; drop table test2; +create table t1 ( +pk int primary key, +dt datetime not null, +da date not null, +ye year not null, +ti time not null, +ts timestamp not null, +index(dt), +index(da), +index(ye), +index(ti), +index(ts) +) engine=ndb; +insert into t1 (pk,dt,da,ye,ti) values +(1, '1901-05-05 23:00:59', '1901-05-05', '1901', '23:00:59'), +(2, '1912-09-05 13:00:59', '1912-09-05', '1912', '13:00:59'), +(3, '1945-12-31 00:00:00', '1945-12-31', '1945', '00:00:00'), +(4, '1955-12-31 00:00:00', '1955-12-31', '1955', '00:00:00'), +(5, '1963-06-06 06:06:06', '1963-06-06', '1963', '06:06:06'), +(6, '1993-06-06 06:06:06', '1993-06-06', '1993', '06:06:06'), +(7, '2001-01-01 10:11:10', '2001-01-01', '2001', '10:11:10'), +(8, '2001-01-01 10:11:11', '2001-01-01', '2001', '10:11:11'), +(9, '2005-01-31 23:59:59', '2005-01-31', '2005', '23:59:59'); +select count(*)-9 from t1 use index (dt) where dt > '1900-01-01 00:00:00'; +count(*)-9 +0 +select count(*)-6 from t1 use index (dt) where dt >= '1955-12-31 00:00:00'; +count(*)-6 +0 +select count(*)-5 from t1 use index (dt) where dt > '1955-12-31 00:00:00'; +count(*)-5 +0 +select count(*)-5 from t1 use index (dt) where dt < '1970-03-03 22:22:22'; +count(*)-5 +0 +select count(*)-7 from t1 use index (dt) where dt < '2001-01-01 10:11:11'; +count(*)-7 +0 +select count(*)-8 from t1 use index (dt) where dt <= '2001-01-01 10:11:11'; +count(*)-8 +0 +select count(*)-9 from t1 use index (dt) where dt <= '2055-01-01 00:00:00'; +count(*)-9 +0 +select count(*)-9 from t1 use index (da) where da > '1900-01-01'; +count(*)-9 +0 +select count(*)-6 from t1 use index (da) where da >= '1955-12-31'; +count(*)-6 +0 +select count(*)-5 from t1 use index (da) where da > '1955-12-31'; +count(*)-5 +0 +select count(*)-5 from t1 use index (da) where da < '1970-03-03'; +count(*)-5 +0 +select count(*)-6 from t1 use index (da) where da < '2001-01-01'; +count(*)-6 +0 +select count(*)-8 from t1 use index (da) where da <= '2001-01-02'; +count(*)-8 +0 +select count(*)-9 from t1 use index (da) where da <= '2055-01-01'; +count(*)-9 +0 +select count(*)-9 from t1 use index (ye) where ye > '1900'; +count(*)-9 +0 +select count(*)-6 from t1 use index (ye) where ye >= '1955'; +count(*)-6 +0 +select count(*)-5 from t1 use index (ye) where ye > '1955'; +count(*)-5 +0 +select count(*)-5 from t1 use index (ye) where ye < '1970'; +count(*)-5 +0 +select count(*)-6 from t1 use index (ye) where ye < '2001'; +count(*)-6 +0 +select count(*)-8 from t1 use index (ye) where ye <= '2001'; +count(*)-8 +0 +select count(*)-9 from t1 use index (ye) where ye <= '2055'; +count(*)-9 +0 +select count(*)-9 from t1 use index (ti) where ti >= '00:00:00'; +count(*)-9 +0 +select count(*)-7 from t1 use index (ti) where ti > '00:00:00'; +count(*)-7 +0 +select count(*)-7 from t1 use index (ti) where ti > '05:05:05'; +count(*)-7 +0 +select count(*)-5 from t1 use index (ti) where ti > '06:06:06'; +count(*)-5 +0 +select count(*)-5 from t1 use index (ti) where ti < '10:11:11'; +count(*)-5 +0 +select count(*)-6 from t1 use index (ti) where ti <= '10:11:11'; +count(*)-6 +0 +select count(*)-8 from t1 use index (ti) where ti < '23:59:59'; +count(*)-8 +0 +select count(*)-9 from t1 use index (ti) where ti <= '23:59:59'; +count(*)-9 +0 diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 151ec404455..62aae177f6a 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -143,3 +143,39 @@ drop table t1; create table t1 (f float(54)); ERROR 42000: Incorrect column specifier for column 'f' drop table if exists t1; +create table t1 (f float(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +Warnings: +Warning 1264 Out of range value adjusted for column 'f' at row 1 +Warning 1264 Out of range value adjusted for column 'f' at row 2 +Warning 1264 Out of range value adjusted for column 'f' at row 3 +Warning 1264 Out of range value adjusted for column 'f' at row 4 +Warning 1264 Out of range value adjusted for column 'f' at row 5 +Warning 1264 Out of range value adjusted for column 'f' at row 6 +select * from t1; +f +-9.999 +-9.999 +-9.999 +9.999 +9.999 +9.999 +drop table if exists t1; +create table t1 (f double(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +Warnings: +Warning 1264 Out of range value adjusted for column 'f' at row 1 +Warning 1264 Out of range value adjusted for column 'f' at row 2 +Warning 1264 Out of range value adjusted for column 'f' at row 3 +Warning 1264 Out of range value adjusted for column 'f' at row 4 +Warning 1264 Out of range value adjusted for column 'f' at row 5 +Warning 1264 Out of range value adjusted for column 'f' at row 6 +select * from t1; +f +-9.999 +-9.999 +-9.999 +9.999 +9.999 +9.999 +drop table if exists t1; diff --git a/mysql-test/r/type_float.result.es b/mysql-test/r/type_float.result.es index 4bfe644d7fb..d1c72a2ee53 100644 --- a/mysql-test/r/type_float.result.es +++ b/mysql-test/r/type_float.result.es @@ -15,8 +15,8 @@ f1 float NULL YES NULL f2 double NULL YES NULL insert into t1 values(10,10),(1e+5,1e+5),(1234567890,1234567890),(1e+10,1e+10),(1e+15,1e+15),(1e+20,1e+20),(1e+50,1e+50),(1e+150,1e+150); Warnings: -Warning 1264 Data truncated; out of range for column 'f1' at row 7 -Warning 1264 Data truncated; out of range for column 'f1' at row 8 +Warning 1264 Out of range value adjusted for column 'f1' at row 7 +Warning 1264 Out of range value adjusted for column 'f1' at row 8 insert into t1 values(-10,-10),(1e-5,1e-5),(1e-10,1e-10),(1e-15,1e-15),(1e-20,1e-20),(1e-50,1e-50),(1e-150,1e-150); select * from t1; f1 f2 @@ -143,3 +143,39 @@ drop table t1; create table t1 (f float(54)); ERROR 42000: Incorrect column specifier for column 'f' drop table if exists t1; +create table t1 (f float(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +Warnings: +Warning 1264 Out of range value adjusted for column 'f' at row 1 +Warning 1264 Out of range value adjusted for column 'f' at row 2 +Warning 1264 Out of range value adjusted for column 'f' at row 3 +Warning 1264 Out of range value adjusted for column 'f' at row 4 +Warning 1264 Out of range value adjusted for column 'f' at row 5 +Warning 1264 Out of range value adjusted for column 'f' at row 6 +select * from t1; +f +-9.999 +-9.999 +-9.999 +9.999 +9.999 +9.999 +drop table if exists t1; +create table t1 (f double(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +Warnings: +Warning 1264 Out of range value adjusted for column 'f' at row 1 +Warning 1264 Out of range value adjusted for column 'f' at row 2 +Warning 1264 Out of range value adjusted for column 'f' at row 3 +Warning 1264 Out of range value adjusted for column 'f' at row 4 +Warning 1264 Out of range value adjusted for column 'f' at row 5 +Warning 1264 Out of range value adjusted for column 'f' at row 6 +select * from t1; +f +-9.999 +-9.999 +-9.999 +9.999 +9.999 +9.999 +drop table if exists t1; diff --git a/mysql-test/t/ndb_index_ordered.test b/mysql-test/t/ndb_index_ordered.test index 42325e25ea3..b7a5b418f44 100644 --- a/mysql-test/t/ndb_index_ordered.test +++ b/mysql-test/t/ndb_index_ordered.test @@ -203,3 +203,67 @@ SELECT s.SubscrID,l.SbclID FROM test1 s left JOIN test2 l ON l.SbcrID=s.SubscrID WHERE s.UsrID=224 order by 1, 2; drop table test1; drop table test2; + +# bug#7424 + bug#7725 + +create table t1 ( + pk int primary key, + dt datetime not null, + da date not null, + ye year not null, + ti time not null, + ts timestamp not null, + index(dt), + index(da), + index(ye), + index(ti), + index(ts) +) engine=ndb; + +insert into t1 (pk,dt,da,ye,ti) values + (1, '1901-05-05 23:00:59', '1901-05-05', '1901', '23:00:59'), + (2, '1912-09-05 13:00:59', '1912-09-05', '1912', '13:00:59'), + (3, '1945-12-31 00:00:00', '1945-12-31', '1945', '00:00:00'), + (4, '1955-12-31 00:00:00', '1955-12-31', '1955', '00:00:00'), + (5, '1963-06-06 06:06:06', '1963-06-06', '1963', '06:06:06'), + (6, '1993-06-06 06:06:06', '1993-06-06', '1993', '06:06:06'), + (7, '2001-01-01 10:11:10', '2001-01-01', '2001', '10:11:10'), + (8, '2001-01-01 10:11:11', '2001-01-01', '2001', '10:11:11'), + (9, '2005-01-31 23:59:59', '2005-01-31', '2005', '23:59:59'); + +# datetime +select count(*)-9 from t1 use index (dt) where dt > '1900-01-01 00:00:00'; +select count(*)-6 from t1 use index (dt) where dt >= '1955-12-31 00:00:00'; +select count(*)-5 from t1 use index (dt) where dt > '1955-12-31 00:00:00'; +select count(*)-5 from t1 use index (dt) where dt < '1970-03-03 22:22:22'; +select count(*)-7 from t1 use index (dt) where dt < '2001-01-01 10:11:11'; +select count(*)-8 from t1 use index (dt) where dt <= '2001-01-01 10:11:11'; +select count(*)-9 from t1 use index (dt) where dt <= '2055-01-01 00:00:00'; + +# date +select count(*)-9 from t1 use index (da) where da > '1900-01-01'; +select count(*)-6 from t1 use index (da) where da >= '1955-12-31'; +select count(*)-5 from t1 use index (da) where da > '1955-12-31'; +select count(*)-5 from t1 use index (da) where da < '1970-03-03'; +select count(*)-6 from t1 use index (da) where da < '2001-01-01'; +select count(*)-8 from t1 use index (da) where da <= '2001-01-02'; +select count(*)-9 from t1 use index (da) where da <= '2055-01-01'; + +# year +select count(*)-9 from t1 use index (ye) where ye > '1900'; +select count(*)-6 from t1 use index (ye) where ye >= '1955'; +select count(*)-5 from t1 use index (ye) where ye > '1955'; +select count(*)-5 from t1 use index (ye) where ye < '1970'; +select count(*)-6 from t1 use index (ye) where ye < '2001'; +select count(*)-8 from t1 use index (ye) where ye <= '2001'; +select count(*)-9 from t1 use index (ye) where ye <= '2055'; + +# time +select count(*)-9 from t1 use index (ti) where ti >= '00:00:00'; +select count(*)-7 from t1 use index (ti) where ti > '00:00:00'; +select count(*)-7 from t1 use index (ti) where ti > '05:05:05'; +select count(*)-5 from t1 use index (ti) where ti > '06:06:06'; +select count(*)-5 from t1 use index (ti) where ti < '10:11:11'; +select count(*)-6 from t1 use index (ti) where ti <= '10:11:11'; +select count(*)-8 from t1 use index (ti) where ti < '23:59:59'; +select count(*)-9 from t1 use index (ti) where ti <= '23:59:59'; diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index 26ac272c6d4..3fe3afa3fac 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -93,3 +93,13 @@ create table t1 (f float(54)); # Should give an error drop table if exists t1; --enable_warnings +# Ensure that maximum values as the result of number of decimals +# being specified in table schema are enforced (Bug #7361) +create table t1 (f float(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +select * from t1; +drop table if exists t1; +create table t1 (f double(4,3)); +insert into t1 values (-11.0),(-11),("-11"),(11.0),(11),("11"); +select * from t1; +drop table if exists t1; diff --git a/ndb/include/kernel/signaldata/DictTabInfo.hpp b/ndb/include/kernel/signaldata/DictTabInfo.hpp index cc8a647615c..93ad246a094 100644 --- a/ndb/include/kernel/signaldata/DictTabInfo.hpp +++ b/ndb/include/kernel/signaldata/DictTabInfo.hpp @@ -266,12 +266,13 @@ public: ExtBinary = NdbSqlUtil::Type::Binary, ExtVarbinary = NdbSqlUtil::Type::Varbinary, ExtDatetime = NdbSqlUtil::Type::Datetime, - ExtTimespec = NdbSqlUtil::Type::Timespec, + ExtDate = NdbSqlUtil::Type::Date, ExtBlob = NdbSqlUtil::Type::Blob, ExtText = NdbSqlUtil::Type::Text, ExtBit = NdbSqlUtil::Type::Bit, ExtLongvarchar = NdbSqlUtil::Type::Longvarchar, - ExtLongvarbinary = NdbSqlUtil::Type::Longvarbinary + ExtLongvarbinary = NdbSqlUtil::Type::Longvarbinary, + ExtTime = NdbSqlUtil::Type::Time }; // Attribute data interpretation @@ -358,10 +359,10 @@ public: AttributeSize = DictTabInfo::an8Bit; AttributeArraySize = 8 * AttributeExtLength; break; - case DictTabInfo::ExtTimespec: + case DictTabInfo::ExtDate: // to fix AttributeSize = DictTabInfo::an8Bit; - AttributeArraySize = 12 * AttributeExtLength; + AttributeArraySize = 3 * AttributeExtLength; break; case DictTabInfo::ExtBlob: case DictTabInfo::ExtText: @@ -380,6 +381,10 @@ public: AttributeSize = DictTabInfo::an8Bit; AttributeArraySize = AttributeExtLength + 2; break; + case DictTabInfo::ExtTime: + AttributeSize = DictTabInfo::an8Bit; + AttributeArraySize = 3 * AttributeExtLength; + break; default: return false; }; diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index fb2a31d6ee2..5d426e5753b 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -22,7 +22,7 @@ * * The NDB Cluster Management API (MGM API) is a C API * that is used to: - * - Start and stop database nodes (DB nodes) + * - Start and stop database nodes (ndbd processes) * - Start and stop NDB Cluster backups * - Control the NDB Cluster log * - Perform other administrative tasks @@ -30,18 +30,23 @@ * @section General Concepts * * Each MGM API function needs a management server handle - * of type Mgm_C_Api::NdbMgmHandle. + * of type @ref NdbMgmHandle. * This handle is initally created by calling the - * function ndb_mgm_create_handle(). + * function ndb_mgm_create_handle() and freed by calling + * ndb_mgm_destroy_handle(). * * A function can return: * -# An integer value. * A value of <b>-1</b> indicates an error. - * -# A pointer value. A <var>NULL</var> value indicates an error; - * otherwise, the return value must be freed by the user of the MGM API. + * -# A non-const pointer value. A <var>NULL</var> value indicates an error; + * otherwise, the return value must be freed + * by the user of the MGM API + * -# A const pointer value. A <var>NULL</var> value indicates an error. + * Returned value should not be freed. * * Error conditions can be identified by using the appropriate - * error-reporting functions. + * error-reporting functions ndb_mgm_get_latest_error() and + * @ref ndb_mgm_error. */ /** @addtogroup MGM_C_API @@ -64,32 +69,54 @@ extern "C" { * NDB Cluster node types */ enum ndb_mgm_node_type { - NDB_MGM_NODE_TYPE_UNKNOWN = -1, /*< Node type not known*/ - NDB_MGM_NODE_TYPE_API = NODE_TYPE_API,/*< An application node (API)*/ - NDB_MGM_NODE_TYPE_NDB = NODE_TYPE_DB, /*< A database node (DB)*/ - NDB_MGM_NODE_TYPE_MGM = NODE_TYPE_MGM,/*< A mgmt server node (MGM)*/ - NDB_MGM_NODE_TYPE_REP = NODE_TYPE_REP,/*< A replication node */ - - NDB_MGM_NODE_TYPE_MIN = 0, /*< Min valid value*/ - NDB_MGM_NODE_TYPE_MAX = 3 /*< Max valid value*/ + NDB_MGM_NODE_TYPE_UNKNOWN = -1 /** Node type not known*/ + ,NDB_MGM_NODE_TYPE_API /** An application node (API) */ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = NODE_TYPE_API +#endif + ,NDB_MGM_NODE_TYPE_NDB /** A database node (DB) */ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = NODE_TYPE_DB +#endif + ,NDB_MGM_NODE_TYPE_MGM /** A mgmt server node (MGM)*/ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + = NODE_TYPE_MGM +#endif +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + ,NDB_MGM_NODE_TYPE_REP = NODE_TYPE_REP /** A replication node */ + ,NDB_MGM_NODE_TYPE_MIN = 0 /** Min valid value*/ + ,NDB_MGM_NODE_TYPE_MAX = 3 /** Max valid value*/ +#endif }; /** * Database node status */ enum ndb_mgm_node_status { - NDB_MGM_NODE_STATUS_UNKNOWN = 0, /*< Node status not known*/ - NDB_MGM_NODE_STATUS_NO_CONTACT = 1, /*< No contact with node*/ - NDB_MGM_NODE_STATUS_NOT_STARTED = 2, /*< Has not run starting protocol*/ - NDB_MGM_NODE_STATUS_STARTING = 3, /*< Is running starting protocol*/ - NDB_MGM_NODE_STATUS_STARTED = 4, /*< Running*/ - NDB_MGM_NODE_STATUS_SHUTTING_DOWN = 5, /*< Is shutting down*/ - NDB_MGM_NODE_STATUS_RESTARTING = 6, /*< Is restarting*/ - NDB_MGM_NODE_STATUS_SINGLEUSER = 7, /*< Maintenance mode*/ - NDB_MGM_NODE_STATUS_RESUME = 8, /*< Resume mode*/ - - NDB_MGM_NODE_STATUS_MIN = 0, /*< Min valid value*/ - NDB_MGM_NODE_STATUS_MAX = 6 /*< Max valid value*/ + /** Node status not known*/ + NDB_MGM_NODE_STATUS_UNKNOWN = 0, + /** No contact with node*/ + NDB_MGM_NODE_STATUS_NO_CONTACT = 1, + /** Has not run starting protocol*/ + NDB_MGM_NODE_STATUS_NOT_STARTED = 2, + /** Is running starting protocol*/ + NDB_MGM_NODE_STATUS_STARTING = 3, + /** Running*/ + NDB_MGM_NODE_STATUS_STARTED = 4, + /** Is shutting down*/ + NDB_MGM_NODE_STATUS_SHUTTING_DOWN = 5, + /** Is restarting*/ + NDB_MGM_NODE_STATUS_RESTARTING = 6, + /** Maintenance mode*/ + NDB_MGM_NODE_STATUS_SINGLEUSER = 7, + /** Resume mode*/ + NDB_MGM_NODE_STATUS_RESUME = 8, +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** Min valid value*/ + NDB_MGM_NODE_STATUS_MIN = 0, + /** Max valid value*/ + NDB_MGM_NODE_STATUS_MAX = 8 +#endif }; /** @@ -128,14 +155,15 @@ extern "C" { NDB_MGM_USAGE_ERROR = 5001 }; +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL struct Ndb_Mgm_Error_Msg { enum ndb_mgm_error code; const char * msg; }; - const struct Ndb_Mgm_Error_Msg ndb_mgm_error_msgs[] = { { NDB_MGM_NO_ERROR, "No error" }, + /* Request for service errors */ { NDB_MGM_ILLEGAL_CONNECT_STRING, "Illegal connect string" }, { NDB_MGM_ILLEGAL_PORT_NUMBER, "Illegal port number" }, { NDB_MGM_ILLEGAL_SOCKET, "Illegal socket" }, @@ -167,66 +195,86 @@ extern "C" { { NDB_MGM_USAGE_ERROR, "Usage error" } }; - const int ndb_mgm_noOfErrorMsgs = sizeof(ndb_mgm_error_msgs)/sizeof(struct Ndb_Mgm_Error_Msg); +#endif /** - * Structure returned by ndb_mgm_get_status + * Status of a node in the cluster + * + * Sub-structure in enum ndb_mgm_cluster_state + * returned by ndb_mgm_get_status() */ struct ndb_mgm_node_state { - int node_id; /*< NDB Cluster node id*/ - enum ndb_mgm_node_type node_type; /*< Type of NDB Cluster node*/ - enum ndb_mgm_node_status node_status; /*< State of node*/ - int start_phase; /*< Start phase. - *< @note Start phase is only - *< valid if - *< node_type is - *< NDB_MGM_NODE_TYPE_NDB and - *< node_status is - *< NDB_MGM_NODE_STATUS_STARTING - */ - int dynamic_id; /*< Id for heartbeats and - *< master take-over - *< (only valid for DB nodes) - */ - int node_group; /*< Node group of node - *< (only valid for DB nodes)*/ - int version; /*< Internal version number*/ - int connect_count; /*< Number of times node has connected - *< or disconnected to the mgm srv - */ - char connect_address[sizeof("000.000.000.000")+1]; + /** NDB Cluster node id*/ + int node_id; + /** Type of NDB Cluster node*/ + enum ndb_mgm_node_type node_type; + /** State of node*/ + enum ndb_mgm_node_status node_status; + /** Start phase. + * + * @note Start phase is only valid if node_type is + * NDB_MGM_NODE_TYPE_NDB and node_status is + * NDB_MGM_NODE_STATUS_STARTING + */ + int start_phase; + /** Id for heartbeats and master take-over (only valid for DB nodes) + */ + int dynamic_id; + /** Node group of node (only valid for DB nodes)*/ + int node_group; + /** Internal version number*/ + int version; + /** Number of times node has connected or disconnected to the + * management server + */ + int connect_count; + /** Ip adress of node when it connected to the management server. + * @note it will be empty if the management server has restarted + * after the node connected. + */ + char connect_address[ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + sizeof("000.000.000.000")+1 +#endif + ]; }; /** - * Cluster status + * State of all nodes in the cluster returned from + * ndb_mgm_get_status() */ struct ndb_mgm_cluster_state { - int no_of_nodes; /*< No of entries in the - *< node_states array - */ - struct ndb_mgm_node_state /*< An array with node_states*/ - node_states[1]; - const char *hostname; + /** No of entries in the node_states array */ + int no_of_nodes; + /** An array with node_states*/ + struct ndb_mgm_node_state node_states[ +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + 1 +#endif + ]; }; /** - * Default reply from the server + * Default reply from the server (for future use, not used today) */ struct ndb_mgm_reply { - int return_code; /*< 0 if successful, - *< otherwise error code. - */ - char message[256]; /*< Error or reply message.*/ + /** 0 if successful, otherwise error code. */ + int return_code; + /** Error or reply message.*/ + char message[256]; }; +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /** * Default information types */ enum ndb_mgm_info { - NDB_MGM_INFO_CLUSTER, /*< ?*/ - NDB_MGM_INFO_CLUSTERLOG /*< Cluster log*/ + /** ?*/ + NDB_MGM_INFO_CLUSTER, + /** Cluster log*/ + NDB_MGM_INFO_CLUSTERLOG }; /** @@ -234,11 +282,16 @@ extern "C" { * (Used only in the development of NDB Cluster.) */ enum ndb_mgm_signal_log_mode { - NDB_MGM_SIGNAL_LOG_MODE_IN, /*< Log receiving signals */ - NDB_MGM_SIGNAL_LOG_MODE_OUT, /*< Log sending signals*/ - NDB_MGM_SIGNAL_LOG_MODE_INOUT, /*< Log both sending/receiving*/ - NDB_MGM_SIGNAL_LOG_MODE_OFF /*< Log off*/ + /** Log receiving signals */ + NDB_MGM_SIGNAL_LOG_MODE_IN, + /** Log sending signals*/ + NDB_MGM_SIGNAL_LOG_MODE_OUT, + /** Log both sending/receiving*/ + NDB_MGM_SIGNAL_LOG_MODE_INOUT, + /** Log off*/ + NDB_MGM_SIGNAL_LOG_MODE_OFF }; +#endif /** * Log severities (used to filter the cluster log) @@ -246,32 +299,31 @@ extern "C" { enum ndb_mgm_clusterlog_level { NDB_MGM_ILLEGAL_CLUSTERLOG_LEVEL = -1, /* must range from 0 and up, indexes into an array */ - NDB_MGM_CLUSTERLOG_ON = 0, /*< Cluster log on*/ - NDB_MGM_CLUSTERLOG_DEBUG = 1, /*< Used in NDB Cluster - *< developement - */ - NDB_MGM_CLUSTERLOG_INFO = 2, /*< Informational messages*/ - NDB_MGM_CLUSTERLOG_WARNING = 3, /*< Conditions that are not - *< error condition, but - *< might require handling - */ - NDB_MGM_CLUSTERLOG_ERROR = 4, /*< Conditions that should be - *< corrected - */ - NDB_MGM_CLUSTERLOG_CRITICAL = 5, /*< Critical conditions, like - *< device errors or out of - *< resources - */ - NDB_MGM_CLUSTERLOG_ALERT = 6, /*< A condition that should be - *< corrected immediately, - *< such as a corrupted system - */ + /** Cluster log on*/ + NDB_MGM_CLUSTERLOG_ON = 0, + /** Used in NDB Cluster developement */ + NDB_MGM_CLUSTERLOG_DEBUG = 1, + /** Informational messages*/ + NDB_MGM_CLUSTERLOG_INFO = 2, + /** Conditions that are not error condition, but might require handling + */ + NDB_MGM_CLUSTERLOG_WARNING = 3, + /** Conditions that should be corrected */ + NDB_MGM_CLUSTERLOG_ERROR = 4, + /** Critical conditions, like device errors or out of resources */ + NDB_MGM_CLUSTERLOG_CRITICAL = 5, + /** A condition that should be corrected immediately, + * such as a corrupted system + */ + NDB_MGM_CLUSTERLOG_ALERT = 6, /* must be next number, works as bound in loop */ - NDB_MGM_CLUSTERLOG_ALL = 7 /*< All severities */ + /** All severities */ + NDB_MGM_CLUSTERLOG_ALL = 7 }; /** - * Log categories + * Log categories, used to set filter on the clusterlog using + * ndb_mgm_set_loglevel_clusterlog() */ enum ndb_mgm_event_category { /** @@ -282,28 +334,56 @@ extern "C" { * Events during all kinds of startups */ NDB_MGM_EVENT_CATEGORY_STARTUP = CFG_LOGLEVEL_STARTUP, - /** * Events during shutdown */ NDB_MGM_EVENT_CATEGORY_SHUTDOWN = CFG_LOGLEVEL_SHUTDOWN, - /** * Transaction statistics (Job level, TCP/IP speed) */ NDB_MGM_EVENT_CATEGORY_STATISTIC = CFG_LOGLEVEL_STATISTICS, + /** + * Events regarding checkpoints + */ NDB_MGM_EVENT_CATEGORY_CHECKPOINT = CFG_LOGLEVEL_CHECKPOINT, + /** + * Events during node restart + */ NDB_MGM_EVENT_CATEGORY_NODE_RESTART = CFG_LOGLEVEL_NODERESTART, + /** + * Events on connection between cluster nodes + */ NDB_MGM_EVENT_CATEGORY_CONNECTION = CFG_LOGLEVEL_CONNECTION, + /** + * Backup events + */ + NDB_MGM_EVENT_CATEGORY_BACKUP = CFG_LOGLEVEL_BACKUP, + /** + * Loglevel debug + */ NDB_MGM_EVENT_CATEGORY_DEBUG = CFG_LOGLEVEL_DEBUG, + /** + * Loglevel info + */ NDB_MGM_EVENT_CATEGORY_INFO = CFG_LOGLEVEL_INFO, + /** + * Loglevel warning + */ NDB_MGM_EVENT_CATEGORY_WARNING = CFG_LOGLEVEL_WARNING, + /** + * Loglevel error + */ NDB_MGM_EVENT_CATEGORY_ERROR = CFG_LOGLEVEL_ERROR, +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + /** + * + */ NDB_MGM_EVENT_CATEGORY_GREP = CFG_LOGLEVEL_GREP, - NDB_MGM_EVENT_CATEGORY_BACKUP = CFG_LOGLEVEL_BACKUP, - +#endif +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL NDB_MGM_MIN_EVENT_CATEGORY = CFG_MIN_LOGLEVEL, NDB_MGM_MAX_EVENT_CATEGORY = CFG_MAX_LOGLEVEL +#endif }; /***************************************************************************/ @@ -384,6 +464,15 @@ extern "C" { * @param connect_string Connect string to the management server, * * @return -1 on error. + * + * @code + * <connectstring> := [<nodeid-specification>,]<host-specification>[,<host-specification>] + * <nodeid-specification> := nodeid=<id> + * <host-specification> := <host>[:<port>] + * <id> is an integer larger than 1 identifying a node in config.ini + * <port> is an integer referring to a regular unix port + * <host> is a string which is a valid Internet host address + * @endcode */ int ndb_mgm_set_connectstring(NdbMgmHandle handle, const char *connect_string); @@ -391,8 +480,8 @@ extern "C" { /** * Get connectstring used for connection * - * @note returns what the connectstring defaults to if the above call has - * not been performed + * @note returns what the connectstring defaults to if the + * ndb_mgm_set_connectstring() call has not been performed * * @param handle Management handle * @@ -401,7 +490,8 @@ extern "C" { const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz); /** - * Connect to a management server + * Connect to a management server. Coonect string is set by + * ndb_mgm_set_connectstring(). * * @param handle Management handle. * @return -1 on error. @@ -422,7 +512,8 @@ extern "C" { * * @param handle Management handle * - * @return node id + * @return node id, 0 indicated that no nodeid has been + * specified */ int ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle); @@ -444,6 +535,7 @@ extern "C" { */ const char *ndb_mgm_get_connected_host(NdbMgmHandle handle); +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /** @} *********************************************************************/ /** * @name Functions: Convert between different data formats @@ -492,7 +584,6 @@ extern "C" { const char * ndb_mgm_get_node_status_string(enum ndb_mgm_node_status status); const char * ndb_mgm_get_clusterlog_level_string(enum ndb_mgm_clusterlog_level); -#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL ndb_mgm_event_category ndb_mgm_match_event_category(const char *); const char * ndb_mgm_get_event_category_string(enum ndb_mgm_event_category); #endif @@ -618,7 +709,7 @@ extern "C" { /** @} *********************************************************************/ /** - * @name Functions: Logging and Statistics + * @name Functions: Logging * @{ */ @@ -670,6 +761,17 @@ extern "C" { enum ndb_mgm_event_category category, int level, struct ndb_mgm_reply* reply); + + /** + * Listen to log events + * + * @param filter pairs of { level, ndb_mgm_event_category } that will be + * pushed to fd, level=0 ends lists + * + * @return fd which events will be pushed to + */ + int ndb_mgm_listen_event(NdbMgmHandle handle, int filter[]); + #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /** * Set log category and levels for the Node @@ -708,9 +810,9 @@ extern "C" { * Start backup * * @param handle NDB management handle. - * @param wait_completed 0=don't wait for confirmation - 1=wait for backup started - 2=wait for backup completed + * @param wait_completed 0=don't wait for confirmation, + * 1=wait for backup started, + * 2=wait for backup completed * @param backup_id Backup id is returned from function. * @param reply Reply message. * @return -1 on error. @@ -760,25 +862,21 @@ extern "C" { int ndb_mgm_exit_single_user(NdbMgmHandle handle, struct ndb_mgm_reply* reply); + /** @} *********************************************************************/ /** - * Listen event - * - * @param filter pairs of { level, category } that will be - * pushed to fd, level=0 ends lists - * - * @return fd which events will be pushed to + * @name Configuration handling + * @{ */ - int ndb_mgm_listen_event(NdbMgmHandle handle, int filter[]); /** * Get configuration * @param handle NDB management handle. * @param version Version of configuration, 0 means latest - * @see MAKE_VERSION + * (which is the only supported input at this point) * * @return configuration * - * @note the caller must call ndb_mgm_detroy_configuration + * @note the caller must call ndb_mgm_destroy_configuration() */ struct ndb_mgm_configuration * ndb_mgm_get_configuration(NdbMgmHandle handle, unsigned version); diff --git a/ndb/include/ndb_constants.h b/ndb/include/ndb_constants.h index 40a3d963955..491d0719a69 100644 --- a/ndb/include/ndb_constants.h +++ b/ndb/include/ndb_constants.h @@ -53,14 +53,15 @@ #define NDB_TYPE_VARCHAR 15 #define NDB_TYPE_BINARY 16 #define NDB_TYPE_VARBINARY 17 -#define NDB_TYPE_DATETIME 18 // need to fix -#define NDB_TYPE_TIMESPEC 19 // need to fix +#define NDB_TYPE_DATETIME 18 +#define NDB_TYPE_DATE 19 #define NDB_TYPE_BLOB 20 #define NDB_TYPE_TEXT 21 #define NDB_TYPE_BIT 22 #define NDB_TYPE_LONG_VARCHAR 23 #define NDB_TYPE_LONG_VARBINARY 24 +#define NDB_TYPE_TIME 25 -#define NDB_TYPE_MAX 25 +#define NDB_TYPE_MAX 26 #endif diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index dcde0a66872..66cd15f190c 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -21,7 +21,7 @@ on http://dev.mysql.com/doc/mysql/en/NDBCluster.html . Some of the fundamental ones are also described in section @ref secConcepts. - The <em>NDB API</em> is a MySQL Cluster application interface + The NDB API is a MySQL Cluster application interface that implements transactions. The NDB API consists of the following fundamental classes: - Ndb_cluster_connection, representing a connection to a cluster, @@ -36,39 +36,38 @@ - NdbDictionary represents meta information about tables and attributes. - NdbError contains the specification for an error. - It is also possible to receive "events" on changed data in the database. + It is also possible to receive "events" triggered when data in the database in changed. This is done through the NdbEventOperation class. - There are also some auxiliary classes. + There are also some auxiliary classes, which are listed in the class hierarchy. The main structure of an application program is as follows: - -# Construct and connect to a cluster using the Ndb_cluster_connection + -# Connect to a cluster using the Ndb_cluster_connection object. - -# Construct and initialize Ndb object(s) to connect to a database. - -# Define and execute transactions using NdbTransaction. + -# Initiate a database connection by constructing and initialising one or more Ndb objects. + -# Define and execute transactions using the NdbTransaction class. -# Delete Ndb objects. - -# Delete cluster connection. + -# Terminate the connection to the cluster (terminate instance of Ndb_cluster_connection). - The main structure of a transaction is as follows: - -# Start transaction (an NdbTransaction) - -# Add and define operations associated with the transaction using - NdbOperation, NdbScanOperation, NdbIndexOperation, NdbIndexScanOperation + The procedure for using transactions is as follows: + -# Start transaction (instantiate an NdbTransaction object) + -# Add and define operations associated with the transaction using the + NdbOperation, NdbScanOperation, NdbIndexOperation, and NdbIndexScanOperation classes. -# Execute transaction The execution can be of two different types, <var>Commit</var> or <var>NoCommit</var>. If the execution is of type <var>NoCommit</var>, then the application program executes part of a transaction, - but without committing the transaction. + but without actually committing the transaction. After executing a <var>NoCommit</var> transaction, the program can continue to add and define more operations to the transaction for later execution. If the execute is of type <var>Commit</var>, then the transaction is - committed. The transaction <em>must</em> be closed after it has been + immediately committed. The transaction <em>must</em> be closed after it has been commited (event if commit fails), and no further addition or definition of - operations is allowed. - + operations for this transaction is allowed. @section secSync Synchronous Transactions @@ -94,12 +93,12 @@ To execute several parallel synchronous transactions, one can either use multiple Ndb objects in several threads, or start multiple - applications programs. + application programs. @section secNdbOperations Operations - Each NdbTransaction consists of a list of operations which are represented - by instances of NdbOperation, NdbScanOperation, NdbIndexOperation, and/or + A NdbTransaction consists of a list of operations, each of which is represented + by an instance of NdbOperation, NdbScanOperation, NdbIndexOperation, or NdbIndexScanOperation. <h3>Single row operations</h3> @@ -111,7 +110,7 @@ -# Specify attribute actions, using NdbOperation::getValue() Here are two brief examples illustrating this process. For the sake of - brevity, we omit error-handling. + brevity, we omit error handling. This first example uses an NdbOperation: @code @@ -150,17 +149,17 @@ creation and use of synchronous transactions. <h4>Step 1: Define single row operation type</h4> - The following types of operations exist: - -# NdbOperation::insertTuple : + The following operation types are supported: + -# NdbOperation::insertTuple() : inserts a non-existing tuple - -# NdbOperation::writeTuple : + -# NdbOperation::writeTuple() : updates an existing tuple if is exists, otherwise inserts a new tuple - -# NdbOperation::updateTuple : + -# NdbOperation::updateTuple() : updates an existing tuple - -# NdbOperation::deleteTuple : + -# NdbOperation::deleteTuple() : deletes an existing tuple - -# NdbOperation::readTuple : + -# NdbOperation::readTuple() : reads an existing tuple with specified lock mode All of these operations operate on the unique tuple key. @@ -172,20 +171,22 @@ NdbTransaction::getNdbIndexOperation() for each operation. <h4>Step 2: Specify Search Conditions</h4> - The search condition is used to select tuples using NdbOperation::equal() + The search condition is used to select tuples. Search conditions are set using NdbOperation::equal(). <h4>Step 3: Specify Attribute Actions</h4> - Now it is time to define which attributes should be read or updated. - Deletes can neither read nor set values, read can only read values and - updates can only set values. - Normally the attribute is defined by its name but it is - also possible to use the attribute identity to define the + Next, it is necessary to determine which attributes should be read or updated. + It is important to remember that: + - Deletes can neither read nor set values, but only delete them + - Reads can only read values + - Updates can only set values + Normally the attribute is identified by name, but it is + also possible to use the attribute's identity to determine the attribute. NdbOperation::getValue() returns an NdbRecAttr object containing the read value. - To get the value, there is actually two methods. - The application can either + To obtain the actual value, one of two methods can be used; + the application can either - use its own memory (passed through a pointer aValue) to NdbOperation::getValue(), or - receive the attribute value in an NdbRecAttr object allocated @@ -193,39 +194,40 @@ The NdbRecAttr object is released when Ndb::closeTransaction() is called. - Thus, the application can not reference this object after - Ndb::closeTransaction() have been called. - The result of reading data from an NdbRecAttr object before - calling NdbTransaction::execute() is undefined. + Thus, the application cannot reference this object following + any subsequent call to Ndb::closeTransaction(). + Attempting to read data from an NdbRecAttr object before + calling NdbTransaction::execute() yields an undefined result. @subsection secScan Scan Operations - Scans are roughly the equivalent of SQL cursors. - - Scans can either be performed on a table (@ref NdbScanOperation) or - on an ordered index (@ref NdbIndexScanOperation). + Scans are roughly the equivalent of SQL cursors, providing a means to + preform high-speed row processing. A scan can be performed + on either a table (using @ref NdbScanOperation) or + an ordered index (by means of an @ref NdbIndexScanOperation). - Scan operation are characteriesed by the following: - - They can only perform reads (shared, exclusive or dirty) + Scan operations are characterised by the following: + - They can perform only reads (shared, exclusive or dirty) - They can potentially work with multiple rows - They can be used to update or delete multiple rows - - They can operate on several nodes in parallell + - They can operate on several nodes in parallel After the operation is created using NdbTransaction::getNdbScanOperation() (or NdbTransaction::getNdbIndexScanOperation()), - it is defined in the following three steps: + it is carried out in the following three steps: -# Define the standard operation type, using NdbScanOperation::readTuples() -# Specify search conditions, using @ref NdbScanFilter and/or @ref NdbIndexScanOperation::setBound() -# Specify attribute actions, using NdbOperation::getValue() -# Executing the transaction, using NdbTransaction::execute() - -# Iterating through the result set using NdbScanOperation::nextResult() + -# Traversing the result set by means of succssive calls to + NdbScanOperation::nextResult() - Here are two brief examples illustrating this process. For the sake of - brevity, we omit error-handling. + Here are two brief examples illustrating this process. Once again, in order + to keep things relatively short and simple, we will forego any error handling. - This first example uses an NdbScanOperation: + This first example performs a table scan, using an NdbScanOperation: @code // 1. Create MyOperation= MyTransaction->getNdbScanOperation("MYTABLENAME"); @@ -244,7 +246,7 @@ MyRecAttr= MyOperation->getValue("ATTR2", NULL); @endcode - The second example uses an NdbIndexScanOperation: + Our second example uses an NdbIndexScanOperation to perform an index scan: @code // 1. Create MyOperation= MyTransaction->getNdbIndexScanOperation("MYORDEREDINDEX", "MYTABLENAME"); @@ -261,98 +263,87 @@ MyRecAttr = MyOperation->getValue("ATTR2", NULL); @endcode - <h4>Step 1: Define scan operation operation type</h4> - Scan operations only support 1 operation, - @ref NdbScanOperation::readTuples() - or @ref NdbIndexScanOperation::readTuples() + Some additional discussion of each step required to perform a scan follows: + + <h4>Step 1: Define Scan Operation Type</h4> + It is important to remember that only a single operation is supported for each scan operation + (@ref NdbScanOperation::readTuples() or @ref NdbIndexScanOperation::readTuples()). @note If you want to define multiple scan operations within the same transaction, then you need to call NdbTransaction::getNdbScanOperation() or - NdbTransaction::getNdbIndexScanOperation() for each operation. + NdbTransaction::getNdbIndexScanOperation() separately for <b>each</b> operation. <h4>Step 2: Specify Search Conditions</h4> The search condition is used to select tuples. If no search condition is specified, the scan will return all rows in the table. - Search condition can be @ref NdbScanFilter which can be used on both - @ref NdbScanOperation and @ref NdbIndexScanOperation or bounds which - can only be used on index scans, @ref NdbIndexScanOperation::setBound. - An index scan can have both NdbScanFilter and bounds + The search condition can be an @ref NdbScanFilter (which can be used on both + @ref NdbScanOperation and @ref NdbIndexScanOperation) or bounds which + can only be used on index scans (@ref NdbIndexScanOperation::setBound()). + An index scan can use both NdbScanFilter and bounds. - @note When NdbScanFilter is used each row is examined but maybe not - returned. But when using bounds, only rows within bounds will be examined. + @note When NdbScanFilter is used, each row is examined, whether or not it is + actually returned. However, when using bounds, only rows within the bounds will be examined. <h4>Step 3: Specify Attribute Actions</h4> - Now it is time to define which attributes should be read. - Normally the attribute is defined by its name but it is - also possible to use the attribute identity to define the - attribute. + Next, it is necessary to define which attributes should be read. + As with transaction attributes, scan attributes are defined by name but it is + also possible to use the attributes' identities to define attributes. - NdbOperation::getValue() returns an NdbRecAttr object - containing the read value. - To get the value, there is actually two methods. - The application can either - - use its own memory (passed through a pointer aValue) to - NdbOperation::getValue(), or - - receive the attribute value in an NdbRecAttr object allocated - by the NDB API. - - The NdbRecAttr object is released when Ndb::closeTransaction() - is called. Thus, the application can not reference this object after - Ndb::closeTransaction() have been called. - The result of reading data from an NdbRecAttr object before - calling NdbTransaction::execute() is undefined. + As previously discussed (see @ref secSync), the value read is returned as + an NdbRecAttr object by the NdbOperation::getValue() method. - <h3> Using Scan to update/delete </h3> - Scanning can also be used to update/delete rows. + <h3>Using Scan to Update/Delete</h3> + Scanning can also be used to update or delete rows. This is performed by - -# Scan using exclusive locks, NdbOperation::LM_Exclusive - -# When iterating through the result set, for each row optionally call + -# Scanning using exclusive locks (using NdbOperation::LM_Exclusive) + -# When iterating through the result set, for each row optionally calling either NdbScanOperation::updateCurrentTuple() or NdbScanOperation::deleteCurrentTuple() - -# If performing NdbScanOperation::updateCurrentTuple(), - set new values on record using ordinary @ref NdbOperation::setValue(). - NdbOperation::equal() should <em>not</em> be called as the primary - key is retreived from the scan. - - @note that the actual update/delete will not be performed until next - NdbTransaction::execute (as with single row operations), - NdbTransaction::execute needs to be called before locks are released, - see @ref secScanLocks - - <h4> Index scans specific features </h4> - The following features are available when performing an index scan - - Scan subset of table using @ref NdbIndexScanOperation::setBound() - - Ordering result set ascending or descending, - @ref NdbIndexScanOperation::readTuples() - - When using NdbIndexScanOperation::BoundEQ on partition key - only fragments containing rows will be scanned. - - Rows are returned unordered unless sorted is set to true. + -# (If performing NdbScanOperation::updateCurrentTuple():) + Setting new values for records simply by using @ref NdbOperation::setValue(). + NdbOperation::equal() should <em>not</em> be called in such cases, as the primary + key is retrieved from the scan. - @note When performing sorted scan, parameter parallelism to - NdbIndexScanOperation::readTuples() will - be ignored and max parallelism will be used instead. + @note The actual update or delete will not be performed until the next + call to NdbTransaction::execute(), just as with single row operations. + NdbTransaction::execute() also must be called before any locks are released; + see @ref secScanLocks for more information. - @subsection secScanLocks Lock handling with scans + <h4>Features Specific to Index Scans</h4> + + When performing an index scan, it is possible to + scan only a subset of a table using @ref NdbIndexScanOperation::setBound(). + In addition, result sets can be sorted in either ascending or descending order, using + @ref NdbIndexScanOperation::readTuples(). Note that rows are returned unordered + by default, that is, unless <var>sorted</var> is set to <b>true</b>. + It is also important to note that, when using NdbIndexScanOperation::BoundEQ + on a partition key, only fragments containing rows will actually be scanned. + + @note When performing a sorted scan, any value passed as the + NdbIndexScanOperation::readTuples() method's <code>parallel</code> argument + will be ignored and maximum parallelism will be used instead. In other words, all + fragments which it is possible to scan will be scanned simultaneously and in parallel + in such cases. - When scanning a table or an index potentially - a lot of records will be returned. + @subsection secScanLocks Lock handling with scans - But Ndb will only lock a batch of rows per fragment at a time. + Performing scans on either a tables or an index has the potential + return a great many records; however, Ndb will lock only a predetermined + number of rows per fragment at a time. How many rows will be locked per fragment is controlled by the - batch parameter to NdbScanOperation::readTuples(). + <var>batch</var> parameter passed to NdbScanOperation::readTuples(). - To let the application handle how locks are released - NdbScanOperation::nextResult() have a parameter fetch_allow. - If NdbScanOperation::nextResult() is called with fetch_allow = false, no - locks may be released as result of the function call. Otherwise the locks - for the current batch may be released. + In order to allow the application to handle how locks are released, + NdbScanOperation::nextResult() has a Boolean parameter <var>fetch_allow</var>. + If NdbScanOperation::nextResult() is called with <var>fetch_allow</var> equal to + <b>false</b>, then no locks may be released as result of the function call. + Otherwise the locks for the current batch may be released. - This example shows scan delete, handling locks in an efficient manner. + This next example shows a scan delete that handle locks in an efficient manner. For the sake of brevity, we omit error-handling. @code int check; @@ -364,40 +355,31 @@ { // Inner loop for each row within batch MyScanOperation->deleteCurrentTuple(); - } while((check = MyScanOperation->nextResult(false) == 0)); + } while((check = MyScanOperation->nextResult(false)) == 0); // When no more rows in batch, exeute all defined deletes MyTransaction->execute(NoCommit); } @endcode - See @ref ndbapi_scan.cpp for full example of scan. + See @ref ndbapi_scan.cpp for a more complete example of a scan. @section secError Error Handling - Errors can occur when - -# operations are being defined, or when the - -# transaction is being executed. - - One recommended way to handle a transaction failure - (i.e. an error is reported) is to: - -# Rollback transaction (NdbTransaction::execute() with a special parameter) - -# Close transaction - -# Restart transaction (if the error was temporary) - - @note Transactions are not automatically closed when an error occur. Call - Ndb::closeTransaction() to close. - - Several errors can occur when a transaction holds multiple - operations which are simultaneously executed. - In this case the application has to go through the operation - objects and query for their NdbError objects to find out what really - happened. - - NdbTransaction::getNdbErrorOperation() returns a reference to the - operation causing the latest error. - NdbTransaction::getNdbErrorLine() delivers the method number of the - erroneous method in the operation. + Errors can occur either when operations making up a transaction are being + defined, or when the transaction is actually being executed. Catching and + handling either sort of error requires testing the value returned by + NdbTransaction::execute(), and then, if an error is indicated (that is, + if this value is equal to -1), using the following two methods in order to + identify the error's type and location: + + - NdbTransaction::getNdbErrorOperation() returns a reference to the + operation causing the most recent error. + - NdbTransaction::getNdbErrorLine() yields the method number of the + erroneous method in the operation. + + This short example illustrates how to detect an error and to use these + two methods to identify it: @code theTransaction = theNdb->startTransaction(); @@ -405,26 +387,43 @@ if (theOperation == NULL) goto error; theOperation->readTuple(NdbOperation::LM_Read); theOperation->setValue("ATTR_1", at1); - theOperation->setValue("ATTR_2", at1); //Here an error occurs + theOperation->setValue("ATTR_2", at1); // Error occurs here theOperation->setValue("ATTR_3", at1); theOperation->setValue("ATTR_4", at1); if (theTransaction->execute(Commit) == -1) { errorLine = theTransaction->getNdbErrorLine(); errorOperation = theTransaction->getNdbErrorOperation(); + } @endcode - Here errorLine will be 3 as the error occurred in the third method - on the operation object. - Getting errorLine == 0 means that the error occurred when executing the - operations. - Here errorOperation will be a pointer to the theOperation object. - NdbTransaction::getNdbError() will return the NdbError object - including holding information about the error. + Here <code>errorLine</code> will be 3, as the error occurred in the + third method called on the NdbOperation object (in this case, + <code>theOperation</code>); if the result of + NdbTransaction::getNdbErrorLine() is 0, this means that the error + occurred when the operations were executed. In this example, + <code>errorOperation</code> will be a pointer to the <code>theOperation</code> + object. The NdbTransaction::getNdbError() method returns an NdbError + object providing information about the error. - Since errors could have occurred even when a commit was reported, - there is also a special method, NdbTransaction::commitStatus(), - to check the commit status of the transaction. + @note Transactions are <b>not</b> automatically closed when an error occurs. Call + Ndb::closeTransaction() to close the transaction. + + One recommended way to handle a transaction failure + (i.e. an error is reported) is to: + -# Rollback transaction (call NdbTransaction::execute() with a special parameter) + -# Close transaction (call NdbTransaction::closeTransaction()) + -# If the error was temporary, attempt to restart the transaction + + Several errors can occur when a transaction contains multiple + operations which are simultaneously executed. + In this case the application has to go through all operations + and query their NdbError objects to find out what really happened. + + It is also important to note that errors can occur even when a commit is + reported as successful. In order to handle such situations, the NDB API + provides an additional NdbTransaction::commitStatus() method to check the + transactions's commit status. ******************************************************************************/ @@ -435,6 +434,10 @@ #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL /** + * @page ndbapi_async.cpp ndbapi_async.cpp + * @include ndbapi_async.cpp + */ +/** * @page ndbapi_async1.cpp ndbapi_async1.cpp * @include ndbapi_async1.cpp */ @@ -455,6 +458,11 @@ * @include ndbapi_scan.cpp */ +/** + * @page ndbapi_event.cpp ndbapi_event.cpp + * @include ndbapi_event.cpp + */ + /** @page secAdapt Adaptive Send Algorithm diff --git a/ndb/include/ndbapi/NdbDictionary.hpp b/ndb/include/ndbapi/NdbDictionary.hpp index 553d85f4129..2100260dab3 100644 --- a/ndb/include/ndbapi/NdbDictionary.hpp +++ b/ndb/include/ndbapi/NdbDictionary.hpp @@ -52,6 +52,7 @@ typedef struct charset_info_st CHARSET_INFO; * -# Dropping secondary indexes (Dictionary::dropIndex) * * NdbDictionary has several help (inner) classes to support this: + * -# NdbDictionary::Dictionary the dictionary handling dictionary objects * -# NdbDictionary::Table for creating tables * -# NdbDictionary::Column for creating table columns * -# NdbDictionary::Index for creating secondary indexes @@ -189,12 +190,13 @@ public: Binary = NDB_TYPE_BINARY, ///< Len Varbinary = NDB_TYPE_VARBINARY, ///< Length bytes: 1, Max: 255 Datetime = NDB_TYPE_DATETIME, ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes ) - Timespec = NDB_TYPE_TIMESPEC, ///< Precision down to 1 nsec(sizeof(Datetime) == 12 bytes ) + Date = NDB_TYPE_DATE, ///< Precision down to 1 day(sizeof(Date) == 4 bytes ) Blob = NDB_TYPE_BLOB, ///< Binary large object (see NdbBlob) Text = NDB_TYPE_TEXT, ///< Text blob Bit = NDB_TYPE_BIT, ///< Bit, length specifies no of bits Longvarchar = NDB_TYPE_LONG_VARCHAR, ///< Length bytes: 2, little-endian - Longvarbinary = NDB_TYPE_LONG_VARBINARY ///< Length bytes: 2, little-endian + Longvarbinary = NDB_TYPE_LONG_VARBINARY, ///< Length bytes: 2, little-endian + Time = NDB_TYPE_TIME ///< Time without date }; /** @@ -909,6 +911,9 @@ public: */ class Event : public Object { public: + /** + * Specifies the type of database operations an Event listens to + */ enum TableEvent { TE_INSERT=1, ///< Insert event on table TE_DELETE=2, ///< Delete event on table @@ -916,6 +921,10 @@ public: TE_ALL=7 ///< Any/all event on table (not relevant when ///< events are received) }; + /** + * Specifies the durability of an event + * (future version may supply other types) + */ enum EventDurability { ED_UNDEFINED #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL @@ -930,8 +939,8 @@ public: // All API's can use it, // But's its removed when ndb is restarted #endif - ,ED_PERMANENT ///< All API's can use it, - ///< It's still defined after a restart + ,ED_PERMANENT ///< All API's can use it. + ///< It's still defined after a cluster system restart #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL = 3 #endif @@ -950,9 +959,12 @@ public: Event(const char *name, const NdbDictionary::Table& table); virtual ~Event(); /** - * Set/get unique identifier for the event + * Set unique identifier for the event */ void setName(const char *name); + /** + * Get unique identifier for the event + */ const char *getName() const; /** * Define table on which events should be detected @@ -967,7 +979,7 @@ public: /** * Set table for which events should be detected * - * @note preferred way is using setTable(const NdbDictionary::Table) + * @note preferred way is using setTable(const NdbDictionary::Table&) * or constructor with table object parameter */ void setTable(const char *tableName); @@ -1224,9 +1236,12 @@ public: #endif /** - * Remove table/index from local cache + * Remove table from local cache */ void removeCachedTable(const char * table); + /** + * Remove index from local cache + */ void removeCachedIndex(const char * index, const char * table); diff --git a/ndb/include/ndbapi/NdbEventOperation.hpp b/ndb/include/ndbapi/NdbEventOperation.hpp index c695b5acd86..4f8a05d589c 100644 --- a/ndb/include/ndbapi/NdbEventOperation.hpp +++ b/ndb/include/ndbapi/NdbEventOperation.hpp @@ -24,73 +24,79 @@ class NdbEventOperationImpl; * @class NdbEventOperation * @brief Class of operations for getting change events from database. * - * An NdbEventOperation object is instantiated by - * Ndb::createEventOperation - * - * Prior to that an event must have been created in the Database through - * NdbDictionary::createEvent - * - * The instance is removed by Ndb::dropEventOperation + * Brief description on how to work with events: + * + * - An event, represented by an NdbDictionary::Event, i created in the + * Database through + * NdbDictionary::Dictionary::createEvent() (note that this can be done + * by any application or thread and not necessarily by the "listener") + * - To listen to events, an NdbEventOperation object is instantiated by + * Ndb::createEventOperation() + * - execute() starts the event flow. Use Ndb::pollEvents() to wait + * for an event to occur. Use next() to iterate + * through the events that have occured. + * - The instance is removed by Ndb::dropEventOperation() * * For more info see: * @ref ndbapi_event.cpp * * Known limitations: * - * Maximum number of active NdbEventOperations are now set at compile time. + * - Maximum number of active NdbEventOperations are now set at compile time. * Today 100. This will become a configuration parameter later. - * - * Maximum number of NdbEventOperations tied to same event are maximum 16 + * - Maximum number of NdbEventOperations tied to same event are maximum 16 * per process. * * Known issues: * - * When several NdbEventOperation's are tied to the same event in the same + * - When several NdbEventOperation's are tied to the same event in the same * process they will share the circular buffer. The BufferLength will then * be the same for all and decided by the first NdbEventOperation * instantiation. Just make sure to instantiate the "largest" one first. - * - * Today all events INSERT/DELETE/UPDATE and all changed attributes are + * - Today all events INSERT/DELETE/UPDATE and all changed attributes are * sent to the API, even if only specific attributes have been specified. * These are however hidden from the user and only relevant data is shown * after next(). - * However false exits from Ndb::pollEvents() may occur and thus + * - "False" exits from Ndb::pollEvents() may occur and thus * the subsequent next() will return zero, * since there was no available data. Just do Ndb::pollEvents() again. - * - * Event code does not check table schema version. Make sure to drop events + * - Event code does not check table schema version. Make sure to drop events * after table is dropped. Will be fixed in later * versions. - * - * If a node failure has occured not all events will be recieved + * - If a node failure has occured not all events will be recieved * anymore. Drop NdbEventOperation and Create again after nodes are up * again. Will be fixed in later versions. * * Test status: - * Tests have been run on 1-node and 2-node systems - * - * Known bugs: * - * None, except if we can call some of the "issues" above bugs + * - Tests have been run on 1-node and 2-node systems * * Useful API programs: * - * ndb_select_all -d sys 'NDB$EVENTS_0' - * Will show contents in the system table containing created events. + * - ndb_select_all -d sys 'NDB$EVENTS_0' + * shows contents in the system table containing created events. * + * @note this is an inteface to viewing events that is subject to change */ class NdbEventOperation { public: /** + * State of the NdbEventOperation object + */ + enum State { + EO_CREATED, ///< Created but execute() not called + EO_EXECUTING, ///< execute() called + EO_ERROR ///< An error has occurred. Object unusable. + }; + /** * Retrieve current state of the NdbEventOperation object */ - enum State {CREATED,EXECUTING,ERROR}; State getState(); /** * Activates the NdbEventOperation to start receiving events. The * changed attribute values may be retrieved after next() has returned - * a value greater than zero. The getValue() methods below must be called + * a value greater than zero. The getValue() methods must be called * prior to execute(). * * @return 0 if successful otherwise -1. @@ -112,21 +118,21 @@ public: * aligned appropriately. The buffer is used directly * (avoiding a copy penalty) only if it is aligned on a * 4-byte boundary and the attribute size in bytes - * (i.e. NdbRecAttr::attrSize times NdbRecAttr::arraySize is + * (i.e. NdbRecAttr::attrSize() times NdbRecAttr::arraySize() is * a multiple of 4). * - * @note There are two versions, NdbOperation::getValue and - * NdbOperation::getPreValue for retrieving the current and + * @note There are two versions, getValue() and + * getPreValue() for retrieving the current and * previous value repectively. * * @note This method does not fetch the attribute value from * the database! The NdbRecAttr object returned by this method * is <em>not</em> readable/printable before the - * NdbEventConnection::execute has been made and - * NdbEventConnection::next has returned a value greater than + * execute() has been made and + * next() has returned a value greater than * zero. If a specific attribute has not changed the corresponding * NdbRecAttr will be in state UNDEFINED. This is checked by - * NdbRecAttr::isNull which then returns -1. + * NdbRecAttr::isNull() which then returns -1. * * @param anAttrName Attribute name * @param aValue If this is non-NULL, then the attribute value @@ -143,11 +149,11 @@ public: /** * Retrieves event resultset if available, inserted into the NdbRecAttrs * specified in getValue() and getPreValue(). To avoid polling for - * a resultset, one can use Ndb::pollEvents + * a resultset, one can use Ndb::pollEvents() * which will wait on a mutex until an event occurs or the specified * timeout occurs. * - * @return >=0 if successful otherwise -1. Return value inicates number + * @return >=0 if successful otherwise -1. Return value indicates number * of available events. By sending pOverRun one may query for buffer * overflow and *pOverRun will indicate the number of events that have * overwritten. diff --git a/ndb/include/util/NdbSqlUtil.hpp b/ndb/include/util/NdbSqlUtil.hpp index feb2b97c54b..75e2a819174 100644 --- a/ndb/include/util/NdbSqlUtil.hpp +++ b/ndb/include/util/NdbSqlUtil.hpp @@ -86,12 +86,13 @@ public: Binary = NDB_TYPE_BINARY, Varbinary = NDB_TYPE_VARBINARY, Datetime = NDB_TYPE_DATETIME, - Timespec = NDB_TYPE_TIMESPEC, + Date = NDB_TYPE_DATE, Blob = NDB_TYPE_BLOB, Text = NDB_TYPE_TEXT, Bit = NDB_TYPE_BIT, Longvarchar = NDB_TYPE_LONG_VARCHAR, - Longvarbinary = NDB_TYPE_LONG_VARBINARY + Longvarbinary = NDB_TYPE_LONG_VARBINARY, + Time = NDB_TYPE_TIME }; Enum m_typeId; // redundant Cmp* m_cmp; // comparison method @@ -153,12 +154,13 @@ private: static Cmp cmpBinary; static Cmp cmpVarbinary; static Cmp cmpDatetime; - static Cmp cmpTimespec; + static Cmp cmpDate; static Cmp cmpBlob; static Cmp cmpText; static Cmp cmpBit; static Cmp cmpLongvarchar; static Cmp cmpLongvarbinary; + static Cmp cmpTime; }; #endif diff --git a/ndb/src/common/util/NdbSqlUtil.cpp b/ndb/src/common/util/NdbSqlUtil.cpp index fd23781605c..1e280ae0fac 100644 --- a/ndb/src/common/util/NdbSqlUtil.cpp +++ b/ndb/src/common/util/NdbSqlUtil.cpp @@ -153,8 +153,8 @@ NdbSqlUtil::m_typeList[] = { cmpDatetime }, { - Type::Timespec, - NULL // cmpTimespec + Type::Date, + cmpDate }, { Type::Blob, @@ -175,6 +175,10 @@ NdbSqlUtil::m_typeList[] = { { Type::Longvarbinary, cmpLongvarbinary + }, + { + Type::Time, + cmpTime } }; @@ -507,19 +511,57 @@ NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const vo return CmpUnknown; } -// allowed but ordering is wrong before wl-1442 done int NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) { - return cmpBinary(info, p1, n1, p2, n2, full); + if (n2 >= sizeof(Int64)) { + Int64 v1, v2; + memcpy(&v1, p1, sizeof(Int64)); + memcpy(&v2, p2, sizeof(Int64)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; } -// not used by MySQL or NDB int -NdbSqlUtil::cmpTimespec(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) { - assert(false); - return 0; +#ifdef ndb_date_is_4_byte_native_int + if (n2 >= sizeof(Int32)) { + Int32 v1, v2; + memcpy(&v1, p1, sizeof(Int32)); + memcpy(&v2, p2, sizeof(Int32)); + if (v1 < v2) + return -1; + if (v1 > v2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +#else + if (n2 >= 4) { // may access 4-th byte + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // from Field_newdate::val_int + Uint64 j1 = uint3korr(v1); + Uint64 j2 = uint3korr(v2); + j1 = (j1 % 32L)+(j1 / 32L % 16L)*100L + (j1/(16L*32L))*10000L; + j2 = (j2 % 32L)+(j2 / 32L % 16L)*100L + (j2/(16L*32L))*10000L; + if (j1 < j2) + return -1; + if (j1 > j2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +#endif } // not supported @@ -538,6 +580,25 @@ NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p return 0; } +int +NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) +{ + if (n2 >= 4) { // may access 4-th byte + const uchar* v1 = (const uchar*)p1; + const uchar* v2 = (const uchar*)p2; + // from Field_time::val_int + Int32 j1 = sint3korr(v1); + Int32 j2 = sint3korr(v2); + if (j1 < j2) + return -1; + if (j1 > j2) + return +1; + return 0; + } + assert(! full); + return CmpUnknown; +} + // not yet int NdbSqlUtil::cmpBit(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full) diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 6d4ca2d9078..5e79fc1c28f 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -2364,7 +2364,8 @@ Dbtc::handle_special_hash(Uint32 dstHash[4], Uint32* src, Uint32 srcLen, */ Uint32 dstLen = xmul * (srcBytes - lb); ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); - uint n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); + int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); + ndbrequire(n != -1); while ((n & 3) != 0) { dstPtr[n++] = 0; } diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 166bd45d48b..a5e01919781 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -629,7 +629,6 @@ ndb_mgm_get_status(NdbMgmHandle handle) malloc(sizeof(ndb_mgm_cluster_state)+ noOfNodes*(sizeof(ndb_mgm_node_state)+sizeof("000.000.000.000#"))); - state->hostname= 0; state->no_of_nodes= noOfNodes; ndb_mgm_node_state * ptr = &state->node_states[0]; int nodeId = 0; @@ -1046,6 +1045,7 @@ struct ndb_mgm_event_categories { "CHECKPOINT", NDB_MGM_EVENT_CATEGORY_CHECKPOINT }, { "DEBUG", NDB_MGM_EVENT_CATEGORY_DEBUG }, { "INFO", NDB_MGM_EVENT_CATEGORY_INFO }, + { "WARNING", NDB_MGM_EVENT_CATEGORY_WARNING }, { "ERROR", NDB_MGM_EVENT_CATEGORY_ERROR }, { "GREP", NDB_MGM_EVENT_CATEGORY_GREP }, { "BACKUP", NDB_MGM_EVENT_CATEGORY_BACKUP }, diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index baa34b2006e..5ffb087cde7 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -1177,7 +1177,14 @@ NdbEventOperation* Ndb::createEventOperation(const char* eventName, tOp = new NdbEventOperation(this, eventName, bufferLength); - if (tOp->getState() != NdbEventOperation::CREATED) { + if (tOp == 0) + { + theError.code= 4000; + return NULL; + } + + if (tOp->getState() != NdbEventOperation::EO_CREATED) { + theError.code= tOp->getNdbError().code; delete tOp; tOp = NULL; } diff --git a/ndb/src/ndbapi/NdbDictionary.cpp b/ndb/src/ndbapi/NdbDictionary.cpp index db912995b5f..4221c22121d 100644 --- a/ndb/src/ndbapi/NdbDictionary.cpp +++ b/ndb/src/ndbapi/NdbDictionary.cpp @@ -956,8 +956,8 @@ operator<<(NdbOut& out, const NdbDictionary::Column& col) case NdbDictionary::Column::Datetime: out << "Datetime"; break; - case NdbDictionary::Column::Timespec: - out << "Timespec"; + case NdbDictionary::Column::Date: + out << "Date"; break; case NdbDictionary::Column::Blob: out << "Blob(" << col.getInlineSize() << "," << col.getPartSize() @@ -967,6 +967,9 @@ operator<<(NdbOut& out, const NdbDictionary::Column& col) out << "Text(" << col.getInlineSize() << "," << col.getPartSize() << ";" << col.getStripeSize() << ";" << csname << ")"; break; + case NdbDictionary::Column::Time: + out << "Time"; + break; case NdbDictionary::Column::Undefined: out << "Undefined"; break; diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 13f9d0c48e1..07a186d8850 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -125,7 +125,7 @@ NdbColumnImpl::init(Type t) case Binary: case Varbinary: case Datetime: - case Timespec: + case Date: m_precision = 0; m_scale = 0; m_length = 1; @@ -143,6 +143,12 @@ NdbColumnImpl::init(Type t) m_length = 4; m_cs = default_cs; break; + case Time: + m_precision = 0; + m_scale = 0; + m_length = 1; + m_cs = NULL; + break; case Bit: m_precision = 0; m_scale = 0; diff --git a/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/ndb/src/ndbapi/NdbEventOperationImpl.cpp index 813a3a5f861..69c05dcb0b7 100644 --- a/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -55,9 +55,8 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N, const char* eventName, const int bufferLength) : NdbEventOperation(*this), m_ndb(theNdb), - m_state(ERROR), m_bufferL(bufferLength) + m_state(EO_ERROR), m_bufferL(bufferLength) { - m_eventId = 0; theFirstRecAttrs[0] = NULL; theCurrentRecAttrs[0] = NULL; @@ -71,16 +70,15 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N, // we should lookup id in Dictionary, TODO // also make sure we only have one listener on each event - if (!m_ndb) { ndbout_c("m_ndb=NULL"); return; } + if (!m_ndb) abort(); NdbDictionary::Dictionary *myDict = m_ndb->getDictionary(); - if (!myDict) { ndbout_c("getDictionary=NULL"); return; } + if (!myDict) { m_error.code= m_ndb->getNdbError().code; return; } const NdbDictionary::Event *myEvnt = myDict->getEvent(eventName); - if (!myEvnt) { ndbout_c("getEvent()=NULL"); return; } + if (!myEvnt) { m_error.code= myDict->getNdbError().code; return; } m_eventImpl = &myEvnt->m_impl; - if (!m_eventImpl) { ndbout_c("m_impl=NULL"); return; } m_bufferHandle = m_ndb->getGlobalEventBufferHandle(); if (m_bufferHandle->m_bufferL > 0) @@ -88,7 +86,7 @@ NdbEventOperationImpl::NdbEventOperationImpl(NdbEventOperation &N, else m_bufferHandle->m_bufferL = m_bufferL; - m_state = CREATED; + m_state = EO_CREATED; } NdbEventOperationImpl::~NdbEventOperationImpl() @@ -106,7 +104,7 @@ NdbEventOperationImpl::~NdbEventOperationImpl() p = p_next; } } - if (m_state == NdbEventOperation::EXECUTING) { + if (m_state == EO_EXECUTING) { stop(); // m_bufferHandle->dropSubscribeEvent(m_bufferId); ; // We should send stop signal here @@ -122,7 +120,7 @@ NdbEventOperationImpl::getState() NdbRecAttr* NdbEventOperationImpl::getValue(const char *colName, char *aValue, int n) { - if (m_state != NdbEventOperation::CREATED) { + if (m_state != EO_CREATED) { ndbout_c("NdbEventOperationImpl::getValue may only be called between instantiation and execute()"); return NULL; } @@ -211,8 +209,8 @@ NdbEventOperationImpl::execute() { NdbDictionary::Dictionary *myDict = m_ndb->getDictionary(); if (!myDict) { - ndbout_c("NdbEventOperation::execute(): getDictionary=NULL"); - return 0; + m_error.code= m_ndb->getNdbError().code; + return -1; } if (theFirstRecAttrs[0] == NULL) { // defaults to get all @@ -245,14 +243,14 @@ NdbEventOperationImpl::execute() if (r) { //Error m_bufferHandle->unprepareAddSubscribeEvent(m_bufferId); - m_state = NdbEventOperation::ERROR; + m_state = EO_ERROR; } else { m_bufferHandle->addSubscribeEvent(m_bufferId, this); - m_state = NdbEventOperation::EXECUTING; + m_state = EO_EXECUTING; } } else { //Error - m_state = NdbEventOperation::ERROR; + m_state = EO_ERROR; } return r; } @@ -261,14 +259,14 @@ int NdbEventOperationImpl::stop() { DBUG_ENTER("NdbEventOperationImpl::stop"); - if (m_state != NdbEventOperation::EXECUTING) + if (m_state != EO_EXECUTING) DBUG_RETURN(-1); // ndbout_c("NdbEventOperation::stopping()"); NdbDictionary::Dictionary *myDict = m_ndb->getDictionary(); if (!myDict) { - ndbout_c("NdbEventOperation::stop(): getDictionary=NULL"); + m_error.code= m_ndb->getNdbError().code; DBUG_RETURN(-1); } @@ -299,13 +297,13 @@ NdbEventOperationImpl::stop() //Error m_bufferHandle->unprepareDropSubscribeEvent(m_bufferId); m_error.code= myDictImpl.m_error.code; - m_state = NdbEventOperation::ERROR; + m_state = EO_ERROR; } else { #ifdef EVENT_DEBUG ndbout_c("NdbEventOperation::dropping()"); #endif m_bufferHandle->dropSubscribeEvent(m_bufferId); - m_state = NdbEventOperation::CREATED; + m_state = EO_CREATED; } DBUG_RETURN(r); diff --git a/ndb/test/include/NdbSchemaOp.hpp b/ndb/test/include/NdbSchemaOp.hpp index ac859f8abe8..e2fb4015b88 100644 --- a/ndb/test/include/NdbSchemaOp.hpp +++ b/ndb/test/include/NdbSchemaOp.hpp @@ -576,7 +576,8 @@ convertColumnTypeToAttrType(NdbDictionary::Column::Type _type) case NdbDictionary::Column::Varbinary: return String; case NdbDictionary::Column::Datetime: - case NdbDictionary::Column::Timespec: + case NdbDictionary::Column::Date: + case NdbDictionary::Column::Time: case NdbDictionary::Column::Undefined: default: return NoAttrTypeDef; diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index 8a09a2ec9d1..0f31a30f1a7 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -1978,7 +1978,7 @@ Val::cmpchars(Par par, const unsigned char* buf1, unsigned len1, const unsigned unsigned len = maxxmulsize * col.m_bytelength; int n1 = NdbSqlUtil::strnxfrm_bug7284(cs, x1, chs->m_xmul * len, buf1, len1); int n2 = NdbSqlUtil::strnxfrm_bug7284(cs, x2, chs->m_xmul * len, buf2, len2); - assert(n1 == n2); + assert(n1 != -1 && n1 == n2); k = memcmp(x1, x2, n1); } else { k = (*cs->coll->strnncollsp)(cs, buf1, len1, buf2, len2, false); diff --git a/ndb/tools/restore/consumer.cpp b/ndb/tools/restore/consumer.cpp index e94c31b2666..4d228230423 100644 --- a/ndb/tools/restore/consumer.cpp +++ b/ndb/tools/restore/consumer.cpp @@ -71,7 +71,10 @@ BackupConsumer::create_table_string(const TableS & table, case NdbDictionary::Column::Datetime: pos += sprintf(buf+pos, "%s", "datetime"); break; - case NdbDictionary::Column::Timespec: + case NdbDictionary::Column::Date: + pos += sprintf(buf+pos, "%s", "date"); + break; + case NdbDictionary::Column::Time: pos += sprintf(buf+pos, "%s", "time"); break; case NdbDictionary::Column::Undefined: diff --git a/pstack/pstack.c b/pstack/pstack.c index 75869686e35..4cdd80d68b5 100644 --- a/pstack/pstack.c +++ b/pstack/pstack.c @@ -1663,7 +1663,7 @@ pr_tag_type (p, name, id, kind) { struct pr_handle *info = (struct pr_handle *) p; const char *t, *tag; - char idbuf[20]; + char idbuf[30]; switch (kind) { diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 975d8dddbb0..9373a888bc2 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -93,10 +93,10 @@ CREATE TABLE IF NOT EXISTS tables_priv ( CREATE TABLE IF NOT EXISTS columns_priv ( Host char(60) DEFAULT '' NOT NULL, - Db char(60) DEFAULT '' NOT NULL, + Db char(64) DEFAULT '' NOT NULL, User char(16) DEFAULT '' NOT NULL, - Table_name char(60) DEFAULT '' NOT NULL, - Column_name char(59) DEFAULT '' NOT NULL, + Table_name char(64) DEFAULT '' NOT NULL, + Column_name char(64) DEFAULT '' NOT NULL, Timestamp timestamp(14), Column_priv set('Select','Insert','Update','References') DEFAULT '' NOT NULL, PRIMARY KEY (Host,Db,User,Table_name,Column_name) diff --git a/sql/field.cc b/sql/field.cc index d15db92e51f..8e0fddae332 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2440,23 +2440,7 @@ int Field_float::store(double nr) int Field_float::store(longlong nr) { - int error= 0; - float j= (float) nr; - if (unsigned_flag && j < 0) - { - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); - j=0; - error= 1; - } -#ifdef WORDS_BIGENDIAN - if (table->db_low_byte_first) - { - float4store(ptr,j); - } - else -#endif - memcpy_fixed(ptr,(byte*) &j,sizeof(j)); - return error; + return store((double)nr); } @@ -2738,23 +2722,7 @@ int Field_double::store(double nr) int Field_double::store(longlong nr) { - double j= (double) nr; - int error= 0; - if (unsigned_flag && j < 0) - { - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); - error= 1; - j=0; - } -#ifdef WORDS_BIGENDIAN - if (table->db_low_byte_first) - { - float8store(ptr,j); - } - else -#endif - doublestore(ptr,j); - return error; + return store((double)nr); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 31b15f89806..0bca8c21715 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3907,7 +3907,7 @@ ha_innobase::create( error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, - !(form->s->db_options_in_use & HA_OPTION_PACK_RECORD)); + form->s->row_type != ROW_TYPE_REDUNDANT); if (error) { innobase_commit_low(trx); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 767ddc40400..b1fbe392940 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2393,13 +2393,15 @@ void ha_ndbcluster::print_results() break; } case NdbDictionary::Column::Datetime: { - // todo - my_snprintf(buf, sizeof(buf), "Datetime ?"); + my_snprintf(buf, sizeof(buf), "Datetime ?"); // fix-me break; } - case NdbDictionary::Column::Timespec: { - // todo - my_snprintf(buf, sizeof(buf), "Timespec ?"); + case NdbDictionary::Column::Date: { + my_snprintf(buf, sizeof(buf), "Date ?"); // fix-me + break; + } + case NdbDictionary::Column::Time: { + my_snprintf(buf, sizeof(buf), "Time ?"); // fix-me break; } case NdbDictionary::Column::Blob: { @@ -3420,6 +3422,9 @@ int ndbcluster_rollback(THD *thd, void *ndb_transaction) Define NDB column based on Field. Returns 0 or mysql error code. Not member of ha_ndbcluster because NDBCOL cannot be declared. + + MySQL text types with character set "binary" are mapped to true + NDB binary types without a character set. This may change. */ static int create_ndb_column(NDBCOL &col, @@ -3495,9 +3500,15 @@ static int create_ndb_column(NDBCOL &col, col.setType(NDBCOL::Datetime); col.setLength(1); break; - case MYSQL_TYPE_DATE: case MYSQL_TYPE_NEWDATE: + col.setType(NDBCOL::Date); + col.setLength(1); + break; case MYSQL_TYPE_TIME: + col.setType(NDBCOL::Time); + col.setLength(1); + break; + case MYSQL_TYPE_DATE: // ? case MYSQL_TYPE_YEAR: col.setType(NDBCOL::Char); col.setLength(field->pack_length()); @@ -3509,7 +3520,7 @@ static int create_ndb_column(NDBCOL &col, col.setType(NDBCOL::Bit); col.setLength(1); } - else if (field->flags & BINARY_FLAG) + else if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) { col.setType(NDBCOL::Binary); col.setLength(field->pack_length()); @@ -3527,7 +3538,7 @@ static int create_ndb_column(NDBCOL &col, Field_varstring* f= (Field_varstring*)field; if (f->length_bytes == 1) { - if (field->flags & BINARY_FLAG) + if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) col.setType(NDBCOL::Varbinary); else { col.setType(NDBCOL::Varchar); @@ -3536,7 +3547,7 @@ static int create_ndb_column(NDBCOL &col, } else if (f->length_bytes == 2) { - if (field->flags & BINARY_FLAG) + if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) col.setType(NDBCOL::Longvarbinary); else { col.setType(NDBCOL::Longvarchar); @@ -3553,7 +3564,7 @@ static int create_ndb_column(NDBCOL &col, // Blob types (all come in as MYSQL_TYPE_BLOB) mysql_type_tiny_blob: case MYSQL_TYPE_TINY_BLOB: - if (field->flags & BINARY_FLAG) + if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) col.setType(NDBCOL::Blob); else { col.setType(NDBCOL::Text); @@ -3566,7 +3577,7 @@ static int create_ndb_column(NDBCOL &col, break; //mysql_type_blob: case MYSQL_TYPE_BLOB: - if (field->flags & BINARY_FLAG) + if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) col.setType(NDBCOL::Blob); else { col.setType(NDBCOL::Text); @@ -3588,7 +3599,7 @@ static int create_ndb_column(NDBCOL &col, break; mysql_type_medium_blob: case MYSQL_TYPE_MEDIUM_BLOB: - if (field->flags & BINARY_FLAG) + if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) col.setType(NDBCOL::Blob); else { col.setType(NDBCOL::Text); @@ -3600,7 +3611,7 @@ static int create_ndb_column(NDBCOL &col, break; mysql_type_long_blob: case MYSQL_TYPE_LONG_BLOB: - if (field->flags & BINARY_FLAG) + if ((field->flags & BINARY_FLAG) && cs == &my_charset_bin) col.setType(NDBCOL::Blob); else { col.setType(NDBCOL::Text); diff --git a/sql/handler.cc b/sql/handler.cc index bbe01dd93d5..b1b741dfee9 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -101,7 +101,7 @@ struct show_table_type_st sys_table_types[]= }; const char *ha_row_type[] = { - "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?" + "", "FIXED", "DYNAMIC", "COMPRESSED", "REDUNDANT", "COMPACT", "?","?","?" }; const char *tx_isolation_names[] = diff --git a/sql/handler.h b/sql/handler.h index b10e6bfe88c..e5a794ca1b2 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -167,7 +167,8 @@ struct show_table_type_st { }; enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, - ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED}; + ROW_TYPE_DYNAMIC, ROW_TYPE_COMPRESSED, + ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT }; /* struct to hold information about the table that should be created */ diff --git a/sql/lex.h b/sql/lex.h index 56d824b7bb8..871d1d99750 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -116,6 +116,7 @@ static SYMBOL symbols[] = { { "COMMENT", SYM(COMMENT_SYM)}, { "COMMIT", SYM(COMMIT_SYM)}, { "COMMITTED", SYM(COMMITTED_SYM)}, + { "COMPACT", SYM(COMPACT_SYM)}, { "COMPRESSED", SYM(COMPRESSED_SYM)}, { "CONCURRENT", SYM(CONCURRENT)}, { "CONDITION", SYM(CONDITION_SYM)}, @@ -378,6 +379,7 @@ static SYMBOL symbols[] = { { "READ", SYM(READ_SYM)}, { "READS", SYM(READS_SYM)}, { "REAL", SYM(REAL)}, + { "REDUNDANT", SYM(REDUNDANT_SYM)}, { "REFERENCES", SYM(REFERENCES)}, { "REGEXP", SYM(REGEXP)}, { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fa23502ea93..6b1456dfbd3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -227,6 +227,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token COLLATION_SYM %token COLUMNS %token COLUMN_SYM +%token COMPACT_SYM %token CONCURRENT %token CONDITION_SYM %token CONNECTION_SYM @@ -381,6 +382,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token READ_SYM %token READS_SYM %token REAL_NUM +%token REDUNDANT_SYM %token REFERENCES %token REGEXP %token RELOAD @@ -2628,7 +2630,9 @@ row_types: DEFAULT { $$= ROW_TYPE_DEFAULT; } | FIXED_SYM { $$= ROW_TYPE_FIXED; } | DYNAMIC_SYM { $$= ROW_TYPE_DYNAMIC; } - | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; }; + | COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; } + | REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; } + | COMPACT_SYM { $$= ROW_TYPE_COMPACT; }; raid_types: RAID_STRIPED_SYM { $$= RAID_TYPE_0; } @@ -6915,6 +6919,7 @@ keyword: | COMMENT_SYM {} | COMMITTED_SYM {} | COMMIT_SYM {} + | COMPACT_SYM {} | COMPRESSED_SYM {} | CONCURRENT {} | CONSISTENT_SYM {} @@ -7046,6 +7051,7 @@ keyword: | RAID_CHUNKSIZE {} | RAID_STRIPED_SYM {} | RAID_TYPE {} + | REDUNDANT_SYM {} | RELAY_LOG_FILE_SYM {} | RELAY_LOG_POS_SYM {} | RELOAD {} |