summaryrefslogtreecommitdiff
path: root/storage/ndb/src/common/util
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/common/util')
-rw-r--r--storage/ndb/src/common/util/Base64.cpp212
-rw-r--r--storage/ndb/src/common/util/BaseString.cpp434
-rw-r--r--storage/ndb/src/common/util/Bitmask.cpp351
-rw-r--r--storage/ndb/src/common/util/ConfigValues.cpp748
-rw-r--r--storage/ndb/src/common/util/File.cpp205
-rw-r--r--storage/ndb/src/common/util/InputStream.cpp61
-rw-r--r--storage/ndb/src/common/util/Makefile.am49
-rw-r--r--storage/ndb/src/common/util/NdbErrHnd.cpp492
-rw-r--r--storage/ndb/src/common/util/NdbOut.cpp173
-rw-r--r--storage/ndb/src/common/util/NdbSqlUtil.cpp1007
-rw-r--r--storage/ndb/src/common/util/OutputStream.cpp99
-rw-r--r--storage/ndb/src/common/util/Parser.cpp350
-rw-r--r--storage/ndb/src/common/util/Properties.cpp1136
-rw-r--r--storage/ndb/src/common/util/SimpleProperties.cpp507
-rw-r--r--storage/ndb/src/common/util/SocketAuthenticator.cpp91
-rw-r--r--storage/ndb/src/common/util/SocketClient.cpp94
-rw-r--r--storage/ndb/src/common/util/SocketServer.cpp345
-rw-r--r--storage/ndb/src/common/util/basestring_vsnprintf.c71
-rw-r--r--storage/ndb/src/common/util/filetest/FileUnitTest.cpp237
-rw-r--r--storage/ndb/src/common/util/filetest/FileUnitTest.hpp41
-rw-r--r--storage/ndb/src/common/util/filetest/Makefile14
-rw-r--r--storage/ndb/src/common/util/getarg.cat3237
-rw-r--r--storage/ndb/src/common/util/md5_hash.cpp239
-rw-r--r--storage/ndb/src/common/util/ndb_init.c35
-rw-r--r--storage/ndb/src/common/util/new.cpp43
-rw-r--r--storage/ndb/src/common/util/random.c284
-rw-r--r--storage/ndb/src/common/util/socket_io.cpp281
-rw-r--r--storage/ndb/src/common/util/strdup.c28
-rw-r--r--storage/ndb/src/common/util/testConfigValues/Makefile12
-rw-r--r--storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp122
-rw-r--r--storage/ndb/src/common/util/testProperties/Makefile9
-rw-r--r--storage/ndb/src/common/util/testProperties/testProperties.cpp195
-rw-r--r--storage/ndb/src/common/util/testSimpleProperties/Makefile12
-rw-r--r--storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp95
-rw-r--r--storage/ndb/src/common/util/uucode.c234
-rw-r--r--storage/ndb/src/common/util/version.c238
36 files changed, 8781 insertions, 0 deletions
diff --git a/storage/ndb/src/common/util/Base64.cpp b/storage/ndb/src/common/util/Base64.cpp
new file mode 100644
index 00000000000..3db911f481f
--- /dev/null
+++ b/storage/ndb/src/common/util/Base64.cpp
@@ -0,0 +1,212 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <Base64.hpp>
+
+static char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+int
+base64_encode(const UtilBuffer &src, BaseString &dst)
+{
+ return base64_encode(src.get_data(), src.length(), dst);
+}
+
+int
+base64_encode(const void * _s, size_t src_len, BaseString &dst) {
+ const unsigned char * s = (const unsigned char*)_s;
+ size_t i = 0;
+ size_t len = 0;
+ while(i < src_len) {
+ if(len == 76){
+ len = 0;
+ dst.append('\n');
+ }
+
+ unsigned c;
+ c = s[i++];
+ c <<= 8;
+
+ if(i < src_len)
+ c += s[i];
+ c <<= 8;
+ i++;
+
+ if(i < src_len)
+ c += s[i];
+ i++;
+
+ dst.append(base64_table[(c >> 18) & 0x3f]);
+ dst.append(base64_table[(c >> 12) & 0x3f]);
+
+ if(i > (src_len + 1))
+ dst.append('=');
+ else
+ dst.append(base64_table[(c >> 6) & 0x3f]);
+
+ if(i > src_len)
+ dst.append('=');
+ else
+ dst.append(base64_table[(c >> 0) & 0x3f]);
+
+ len += 4;
+ }
+ return 0;
+}
+
+static inline unsigned
+pos(unsigned char c) {
+ return strchr(base64_table, c) - base64_table;
+}
+
+
+int
+base64_decode(const BaseString &src, UtilBuffer &dst) {
+ return base64_decode(src.c_str(), src.length(), dst);
+}
+
+#define SKIP_SPACE(src, i, size){ \
+ while(i < size && isspace(* src)){ \
+ i++; \
+ src++; \
+ } \
+ if(i == size){ \
+ i = size + 1; \
+ break; \
+ } \
+}
+
+int
+base64_decode(const char * src, size_t size, UtilBuffer &dst) {
+ size_t i = 0;
+ while(i < size){
+ unsigned c = 0;
+ int mark = 0;
+
+ SKIP_SPACE(src, i, size);
+
+ c += pos(*src++);
+ c <<= 6;
+ i++;
+
+ SKIP_SPACE(src, i, size);
+
+ c += pos(*src++);
+ c <<= 6;
+ i++;
+
+ SKIP_SPACE(src, i, size);
+
+ if(* src != '=')
+ c += pos(*src++);
+ else {
+ i = size;
+ mark = 2;
+ c <<= 6;
+ goto end;
+ }
+ c <<= 6;
+ i++;
+
+ SKIP_SPACE(src, i, size);
+
+ if(*src != '=')
+ c += pos(*src++);
+ else {
+ i = size;
+ mark = 1;
+ goto end;
+ }
+ i++;
+
+ end:
+ char b[3];
+ b[0] = (c >> 16) & 0xff;
+ b[1] = (c >> 8) & 0xff;
+ b[2] = (c >> 0) & 0xff;
+
+ dst.append((void *)b, 3-mark);
+ }
+
+ if(i != size){
+ abort();
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef __TEST__B64
+/**
+ * USER_FLAGS="-D__TEST__B64" make Base64.o && g++ Base64.o BaseString.o
+ */
+inline
+void
+require(bool b){
+ if(!b)
+ abort();
+}
+
+int
+main(void){
+ for(int i = 0; i < 500; i++){
+ const size_t len = rand() % 10000 + 1;
+ UtilBuffer src;
+ for(size_t j = 0; j<len; j++){
+ char c = rand();
+ src.append(&c, 1);
+ }
+ require(src.length() == len);
+
+ BaseString str;
+ require(base64_encode(src, str) == 0);
+
+ if(str.length() == 3850){
+ printf(">%s<\n", str.c_str());
+ }
+
+ UtilBuffer dst;
+ require(base64_decode(str, dst) == 0);
+ require(dst.length() == src.length());
+
+ const char * c_src = (char*)src.get_data();
+ const char * c_dst = (char*)dst.get_data();
+ if(memcmp(src.get_data(), dst.get_data(), src.length()) != 0){
+ printf("-- src --\n");
+ for(int i2 = 0; i2<len; i2++){
+ unsigned char c = c_src[i2];
+ printf("%.2x ", (unsigned)c);
+ if((i2 % 8) == 7)
+ printf("\n");
+ }
+ printf("\n");
+
+ printf("-- dst --\n");
+ for(int i2 = 0; i2<len; i2++){
+ unsigned char c = c_dst[i2];
+ printf("%.2x ", (unsigned)c);
+ if((i2 % 8) == 7)
+ printf("\n");
+ }
+ printf("\n");
+ abort();
+ }
+ }
+ return 0;
+}
+
+#endif
diff --git a/storage/ndb/src/common/util/BaseString.cpp b/storage/ndb/src/common/util/BaseString.cpp
new file mode 100644
index 00000000000..dbff44c377d
--- /dev/null
+++ b/storage/ndb/src/common/util/BaseString.cpp
@@ -0,0 +1,434 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* -*- c-basic-offset: 4; -*- */
+#include <ndb_global.h>
+#include <BaseString.hpp>
+#include <basestring_vsnprintf.h>
+
+BaseString::BaseString()
+{
+ m_chr = new char[1];
+ m_chr[0] = 0;
+ m_len = 0;
+}
+
+BaseString::BaseString(const char* s)
+{
+ const size_t n = strlen(s);
+ m_chr = new char[n + 1];
+ memcpy(m_chr, s, n + 1);
+ m_len = n;
+}
+
+BaseString::BaseString(const BaseString& str)
+{
+ const char* const s = str.m_chr;
+ const size_t n = str.m_len;
+ char* t = new char[n + 1];
+ memcpy(t, s, n + 1);
+ m_chr = t;
+ m_len = n;
+}
+
+BaseString::~BaseString()
+{
+ delete[] m_chr;
+}
+
+BaseString&
+BaseString::assign(const char* s)
+{
+ const size_t n = strlen(s);
+ char* t = new char[n + 1];
+ memcpy(t, s, n + 1);
+ delete[] m_chr;
+ m_chr = t;
+ m_len = n;
+ return *this;
+}
+
+BaseString&
+BaseString::assign(const char* s, size_t n)
+{
+ char* t = new char[n + 1];
+ memcpy(t, s, n);
+ t[n] = 0;
+ delete[] m_chr;
+ m_chr = t;
+ m_len = n;
+ return *this;
+}
+
+BaseString&
+BaseString::assign(const BaseString& str, size_t n)
+{
+ if (n > str.m_len)
+ n = str.m_len;
+ return assign(str.m_chr, n);
+}
+
+BaseString&
+BaseString::append(const char* s)
+{
+ const size_t n = strlen(s);
+ char* t = new char[m_len + n + 1];
+ memcpy(t, m_chr, m_len);
+ memcpy(t + m_len, s, n + 1);
+ delete[] m_chr;
+ m_chr = t;
+ m_len += n;
+ return *this;
+}
+
+BaseString&
+BaseString::append(char c) {
+ return appfmt("%c", c);
+}
+
+BaseString&
+BaseString::append(const BaseString& str)
+{
+ return append(str.m_chr);
+}
+
+BaseString&
+BaseString::append(const Vector<BaseString> &vector,
+ const BaseString &separator) {
+ for(size_t i=0;i<vector.size(); i++) {
+ append(vector[i]);
+ if(i<vector.size()-1)
+ append(separator);
+ }
+ return *this;
+}
+
+BaseString&
+BaseString::assfmt(const char *fmt, ...)
+{
+ char buf[1];
+ va_list ap;
+ int l;
+
+ /* Figure out how long the formatted string will be. A small temporary
+ * buffer is used, because I don't trust all implementations to work
+ * when called as vsnprintf(NULL, 0, ...).
+ */
+ va_start(ap, fmt);
+ l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1;
+ va_end(ap);
+ if(l > (int)m_len) {
+ delete[] m_chr;
+ m_chr = new char[l];
+ }
+ va_start(ap, fmt);
+ basestring_vsnprintf(m_chr, l, fmt, ap);
+ va_end(ap);
+ m_len = strlen(m_chr);
+ return *this;
+}
+
+BaseString&
+BaseString::appfmt(const char *fmt, ...)
+{
+ char buf[1];
+ va_list ap;
+ int l;
+
+ /* Figure out how long the formatted string will be. A small temporary
+ * buffer is used, because I don't trust all implementations to work
+ * when called as vsnprintf(NULL, 0, ...).
+ */
+ va_start(ap, fmt);
+ l = basestring_vsnprintf(buf, sizeof(buf), fmt, ap) + 1;
+ va_end(ap);
+ char *tmp = new char[l];
+ va_start(ap, fmt);
+ basestring_vsnprintf(tmp, l, fmt, ap);
+ va_end(ap);
+ append(tmp);
+ delete[] tmp;
+ return *this;
+}
+
+BaseString&
+BaseString::operator=(const BaseString& str)
+{
+ if (this != &str) {
+ this->assign(str);
+ }
+ return *this;
+}
+
+int
+BaseString::split(Vector<BaseString> &v,
+ const BaseString &separator,
+ int maxSize) const {
+ char *str = strdup(m_chr);
+ int i, start, len, num = 0;
+ len = strlen(str);
+ for(start = i = 0;
+ (i <= len) && ( (maxSize<0) || ((int)v.size()<=maxSize-1) );
+ i++) {
+ if(strchr(separator.c_str(), str[i]) || i == len) {
+ if(maxSize < 0 || (int)v.size() < maxSize-1)
+ str[i] = '\0';
+ v.push_back(BaseString(str+start));
+ num++;
+ start = i+1;
+ }
+ }
+ free(str);
+
+ return num;
+}
+
+ssize_t
+BaseString::indexOf(char c) {
+ char *p;
+ p = strchr(m_chr, c);
+ if(p == NULL)
+ return -1;
+ return (ssize_t)(p-m_chr);
+}
+
+ssize_t
+BaseString::lastIndexOf(char c) {
+ char *p;
+ p = strrchr(m_chr, c);
+ if(p == NULL)
+ return -1;
+ return (ssize_t)(p-m_chr);
+}
+
+BaseString
+BaseString::substr(ssize_t start, ssize_t stop) {
+ if(stop < 0)
+ stop = length();
+ ssize_t len = stop-start;
+ if(len <= 0)
+ return BaseString("");
+ BaseString s;
+ s.assign(m_chr+start, len);
+ return s;
+}
+
+static bool
+iswhite(char c) {
+ switch(c) {
+ case ' ':
+ case '\t':
+ return true;
+ default:
+ return false;
+ }
+ /* NOTREACHED */
+}
+
+char **
+BaseString::argify(const char *argv0, const char *src) {
+ Vector<char *> vargv;
+
+ if(argv0 != NULL)
+ vargv.push_back(strdup(argv0));
+
+ char *tmp = new char[strlen(src)+1];
+ char *dst = tmp;
+ const char *end = src + strlen(src);
+ /* Copy characters from src to destination, while compacting them
+ * so that all whitespace is compacted and replaced by a NUL-byte.
+ * At the same time, add pointers to strings in the vargv vector.
+ * When whitespace is detected, the characters '"' and '\' are honored,
+ * to make it possible to give arguments containing whitespace.
+ * The semantics of '"' and '\' match that of most Unix shells.
+ */
+ while(src < end && *src) {
+ /* Skip initial whitespace */
+ while(src < end && *src && iswhite(*src))
+ src++;
+
+ char *begin = dst;
+ while(src < end && *src) {
+ /* Handle '"' quotation */
+ if(*src == '"') {
+ src++;
+ while(src < end && *src && *src != '"') {
+ if(*src == '\\')
+ src++;
+ *dst++ = *src++;
+ }
+ src++;
+ if(src >= end)
+ goto end;
+ }
+
+ /* Handle '\' */
+ if(*src == '\\')
+ src++;
+ else if(iswhite(*src))
+ break;
+
+ /* Actually copy characters */
+ *dst++ = *src++;
+ }
+
+ /* Make sure the string is properly terminated */
+ *dst++ = '\0';
+ src++;
+
+ vargv.push_back(strdup(begin));
+ }
+ end:
+
+ delete[] tmp;
+ vargv.push_back(NULL);
+
+ /* Convert the C++ Vector into a C-vector of strings, suitable for
+ * calling execv().
+ */
+ char **argv = (char **)malloc(sizeof(*argv) * (vargv.size()));
+ if(argv == NULL)
+ return NULL;
+
+ for(size_t i = 0; i < vargv.size(); i++){
+ argv[i] = vargv[i];
+ }
+
+ return argv;
+}
+
+BaseString&
+BaseString::trim(const char * delim){
+ trim(m_chr, delim);
+ m_len = strlen(m_chr);
+ return * this;
+}
+
+char*
+BaseString::trim(char * str, const char * delim){
+ int len = strlen(str) - 1;
+ for(; len > 0 && strchr(delim, str[len]); len--);
+
+ int pos = 0;
+ for(; pos <= len && strchr(delim, str[pos]); pos++);
+
+ if(pos > len){
+ str[0] = 0;
+ return 0;
+ } else {
+ memmove(str, &str[pos], len - pos + 1);
+ str[len-pos+1] = 0;
+ }
+
+ return str;
+}
+
+int
+BaseString::vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ return(basestring_vsnprintf(str, size, format, ap));
+}
+
+int
+BaseString::snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int ret= basestring_vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return(ret);
+}
+
+
+#ifdef TEST_BASE_STRING
+
+/*
+g++ -g -Wall -o tbs -DTEST_BASE_STRING -I$NDB_TOP/include/util \
+ -I$NDB_TOP/include/portlib BaseString.cpp
+valgrind ./tbs
+*/
+
+int main()
+{
+ BaseString s("abc");
+ BaseString t(s);
+ s.assign("def");
+ t.append("123");
+ assert(s == "def");
+ assert(t == "abc123");
+ s.assign("");
+ t.assign("");
+ for (unsigned i = 0; i < 1000; i++) {
+ s.append("xyz");
+ t.assign(s);
+ assert(strlen(t.c_str()) % 3 == 0);
+ }
+
+ {
+ BaseString s(":123:abc:;:foo:");
+ Vector<BaseString> v;
+ assert(s.split(v, ":;") == 7);
+
+ assert(v[0] == "");
+ assert(v[1] == "123");
+ assert(v[2] == "abc");
+ assert(v[3] == "");
+ assert(v[4] == "");
+ assert(v[5] == "foo");
+ assert(v[6] == "");
+ }
+
+ {
+ BaseString s(":123:abc:foo:bar");
+ Vector<BaseString> v;
+ assert(s.split(v, ":;", 4) == 4);
+
+ assert(v[0] == "");
+ assert(v[1] == "123");
+ assert(v[2] == "abc");
+ assert(v[3] == "foo:bar");
+
+ BaseString n;
+ n.append(v, "()");
+ assert(n == "()123()abc()foo:bar");
+ n = "";
+ n.append(v);
+ assert(n == " 123 abc foo:bar");
+ }
+
+ {
+ assert(BaseString("hamburger").substr(4,2) == "");
+ assert(BaseString("hamburger").substr(3) == "burger");
+ assert(BaseString("hamburger").substr(4,8) == "urge");
+ assert(BaseString("smiles").substr(1,5) == "mile");
+ assert(BaseString("012345").indexOf('2') == 2);
+ assert(BaseString("hej").indexOf('X') == -1);
+ }
+
+ {
+ assert(BaseString(" 1").trim(" ") == "1");
+ assert(BaseString("1 ").trim(" ") == "1");
+ assert(BaseString(" 1 ").trim(" ") == "1");
+ assert(BaseString("abc\t\n\r kalleabc\t\r\n").trim("abc\t\r\n ") == "kalle");
+ assert(BaseString(" ").trim(" ") == "");
+ }
+ return 0;
+}
+
+#endif
+
+template class Vector<char *>;
+template class Vector<BaseString>;
diff --git a/storage/ndb/src/common/util/Bitmask.cpp b/storage/ndb/src/common/util/Bitmask.cpp
new file mode 100644
index 00000000000..0aa39a37204
--- /dev/null
+++ b/storage/ndb/src/common/util/Bitmask.cpp
@@ -0,0 +1,351 @@
+#include <Bitmask.hpp>
+#include <NdbOut.hpp>
+
+static
+void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
+{
+ printf("b'");
+ for(unsigned i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
+ printf("1");
+ else
+ printf("0");
+ if((i & 31) == 31)
+ printf(" ");
+ }
+}
+
+#ifndef __TEST_BITMASK__
+
+void
+BitmaskImpl::getFieldImpl(const Uint32 src[],
+ unsigned shiftL, unsigned len, Uint32 dst[])
+{
+ assert(shiftL < 32);
+
+ unsigned shiftR = 32 - shiftL;
+ unsigned undefined = shiftL ? ~0 : 0;
+
+ * dst = shiftL ? * dst : 0;
+
+ while(len >= 32)
+ {
+ * dst++ |= (* src) << shiftL;
+ * dst = ((* src++) >> shiftR) & undefined;
+ len -= 32;
+ }
+
+ if(len < shiftR)
+ {
+ * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
+ }
+ else
+ {
+ * dst++ |= ((* src) << shiftL);
+ * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
+ }
+}
+
+void
+BitmaskImpl::setFieldImpl(Uint32 dst[],
+ unsigned shiftL, unsigned len, const Uint32 src[])
+{
+ /**
+ *
+ * abcd ef00
+ * 00ab cdef
+ */
+ assert(shiftL < 32);
+ unsigned shiftR = 32 - shiftL;
+ unsigned undefined = shiftL ? ~0 : 0;
+ while(len >= 32)
+ {
+ * dst = (* src++) >> shiftL;
+ * dst++ |= ((* src) << shiftR) & undefined;
+ len -= 32;
+ }
+
+ Uint32 mask = ((1 << len) -1);
+ * dst = (* dst & ~mask);
+ if(len < shiftR)
+ {
+ * dst |= ((* src++) >> shiftL) & mask;
+ }
+ else
+ {
+ * dst |= ((* src++) >> shiftL);
+ * dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ;
+ }
+}
+#else
+
+#define DEBUG 0
+#include <Vector.hpp>
+static void do_test(int bitmask_size);
+
+int
+main(int argc, char** argv)
+{
+ int loops = argc > 1 ? atoi(argv[1]) : 1000;
+ int max_size = argc > 2 ? atoi(argv[2]) : 1000;
+
+
+ for(int i = 0; i<loops; i++)
+ do_test(1 + (rand() % max_size));
+}
+
+struct Alloc
+{
+ Uint32 pos;
+ Uint32 size;
+ Vector<Uint32> data;
+};
+
+static void require(bool b)
+{
+ if(!b) abort();
+}
+
+static
+bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
+{
+ Uint32 sz32 = (len + 31) >> 5;
+ for(int i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
+ return false;
+ }
+ return true;
+}
+
+
+static int val_pos = 0;
+static int val[] = { 384, 241, 32,
+ 1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0,
+ 241 };
+
+static int lrand()
+{
+#if 0
+ return val[val_pos++];
+#else
+ return rand();
+#endif
+}
+
+static
+void rand(Uint32 dst[], Uint32 len)
+{
+ for(int i = 0; i<len; i++)
+ BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
+}
+
+static
+void simple(int pos, int size)
+{
+ ndbout_c("simple pos: %d size: %d", pos, size);
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+ Uint32 sz32 = (size + pos + 32) >> 5;
+ const Uint32 sz = 4 * sz32;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ memset(src, 0x0, sz);
+ memset(dst, 0x0, sz);
+ memset(mask, 0xFF, sz);
+ rand(src, size);
+ BitmaskImpl::setField(sz32, mask, pos, size, src);
+ BitmaskImpl::getField(sz32, mask, pos, size, dst);
+ printf("src: "); print(src, size+31); printf("\n");
+ printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
+ printf("dst: "); print(dst, size+31); printf("\n");
+ require(cmp(src, dst, size+31));
+};
+
+static
+void simple2(int size, int loops)
+{
+ ndbout_c("simple2 %d - ", size);
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+
+ Uint32 sz32 = (size + 32) >> 5;
+ Uint32 sz = sz32 << 2;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ Vector<Uint32> save;
+ for(int i = 0; i<loops; i++)
+ {
+ memset(mask, 0xFF, sz);
+ memset(dst, 0xFF, sz);
+ int len;
+ int pos = 0;
+ while(pos+1 < size)
+ {
+ memset(src, 0xFF, sz);
+ while(!(len = rand() % (size - pos)));
+ BitmaskImpl::setField(sz32, mask, pos, len, src);
+ if(memcmp(dst, mask, sz))
+ {
+ ndbout_c("pos: %d len: %d", pos, len);
+ print(mask, size);
+ abort();
+ }
+ printf("[ %d %d ]", pos, len);
+ save.push_back(pos);
+ save.push_back(len);
+ pos += len;
+ }
+
+ for(int j = 0; j<save.size(); )
+ {
+ pos = save[j++];
+ len = save[j++];
+ memset(src, 0xFF, sz);
+ BitmaskImpl::getField(sz32, mask, pos, len, src);
+ if(memcmp(dst, src, sz))
+ {
+ ndbout_c("pos: %d len: %d", pos, len);
+ printf("src: "); print(src, size); printf("\n");
+ printf("dst: "); print(dst, size); printf("\n");
+ printf("msk: "); print(mask, size); printf("\n");
+ abort();
+ }
+ }
+ ndbout_c("");
+ }
+}
+
+static void
+do_test(int bitmask_size)
+{
+#if 1
+ simple(rand() % 33, (rand() % 63)+1);
+//#else
+ Vector<Alloc> alloc_list;
+ bitmask_size = (bitmask_size + 31) & ~31;
+ Uint32 sz32 = (bitmask_size >> 5);
+ Vector<Uint32> alloc_mask;
+ Vector<Uint32> test_mask;
+
+ ndbout_c("Testing bitmask of size %d", bitmask_size);
+ Uint32 zero = 0;
+ alloc_mask.fill(sz32, zero);
+ test_mask.fill(sz32, zero);
+
+ for(int i = 0; i<5000; i++)
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ int pos = lrand() % (bitmask_size - 1);
+ int free = 0;
+ if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
+ {
+ // Bit was allocated
+ // 1) Look up allocation
+ // 2) Check data
+ // 3) free it
+ size_t j;
+ int min, max;
+ for(j = 0; j<alloc_list.size(); j++)
+ {
+ min = alloc_list[j].pos;
+ max = min + alloc_list[j].size;
+ if(pos >= min && pos < max)
+ {
+ break;
+ }
+ }
+ require(pos >= min && pos < max);
+ BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
+ tmp.getBase());
+ if(DEBUG)
+ {
+ printf("freeing [ %d %d ]", min, max);
+ printf("- mask: ");
+ print(tmp.getBase(), max - min);
+
+ printf(" save: ");
+ size_t k;
+ Alloc& a = alloc_list[j];
+ for(k = 0; k<a.data.size(); k++)
+ printf("%.8x ", a.data[k]);
+ printf("\n");
+ }
+ int bytes = (max - min + 7) >> 3;
+ if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
+ {
+ abort();
+ }
+ while(min < max)
+ BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
+ alloc_list.erase(j);
+ }
+ else
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ // Bit was free
+ // 1) Check how much space is avaiable
+ // 2) Create new allocation of lrandom size
+ // 3) Fill data with lrandom data
+ // 4) Update alloc mask
+ while(pos+free < bitmask_size &&
+ !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
+ free++;
+
+ Uint32 sz =
+ (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
+ sz = sz ? sz : 1;
+ sz = pos + sz == bitmask_size ? sz - 1 : sz;
+ Alloc a;
+ a.pos = pos;
+ a.size = sz;
+ a.data.fill(((sz+31)>> 5)-1, zero);
+ if(DEBUG)
+ printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
+ for(size_t j = 0; j<sz; j++)
+ {
+ BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
+ if((lrand() % 1000) > 500)
+ BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
+ }
+ if(DEBUG)
+ {
+ printf("- mask: ");
+ print(a.data.getBase(), sz);
+ printf("\n");
+ }
+ BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
+ a.data.getBase());
+ alloc_list.push_back(a);
+ }
+ }
+#endif
+}
+
+template class Vector<Alloc>;
+template class Vector<Uint32>;
+
+#endif
diff --git a/storage/ndb/src/common/util/ConfigValues.cpp b/storage/ndb/src/common/util/ConfigValues.cpp
new file mode 100644
index 00000000000..5c4b17c73ca
--- /dev/null
+++ b/storage/ndb/src/common/util/ConfigValues.cpp
@@ -0,0 +1,748 @@
+
+#include <ndb_global.h>
+#include <ConfigValues.hpp>
+#include <NdbOut.hpp>
+#include <NdbTCP.h>
+
+static Uint32 hash(Uint32 key, Uint32 size);
+static Uint32 nextHash(Uint32 key, Uint32 size, Uint32 pos, Uint32 count);
+static bool findKey(const Uint32 * vals, Uint32 sz, Uint32 key, Uint32 * pos);
+
+/**
+ * Key
+ *
+ * t = Type - 4 bits 0-15
+ * s = Section - 14 bits 0-16383
+ * k = Key value - 14 bits 0-16383
+ *
+ * 1111111111222222222233
+ * 01234567890123456789012345678901
+ * kkkkkkkkkkkkkkssssssssssssssoooo
+ */
+#define KP_TYPE_MASK (15)
+#define KP_TYPE_SHIFT (28)
+#define KP_SECTION_MASK (0x3FFF)
+#define KP_SECTION_SHIFT (14)
+#define KP_KEYVAL_MASK (0x3FFF)
+#define KP_KEYVAL_SHIFT (0)
+#define KP_MASK (0x0FFFFFFF)
+
+static const Uint32 CFV_KEY_PARENT = (KP_KEYVAL_MASK - 1);
+static const Uint32 CFV_KEY_FREE = ~0;
+
+static const char Magic[] = { 'N', 'D', 'B', 'C', 'O', 'N', 'F', 'V' };
+
+//#define DEBUG_CV
+#ifdef DEBUG_CV
+#define DEBUG
+#else
+#define DEBUG if(0)
+#endif
+
+inline
+ConfigValues::ValueType
+getTypeOf(Uint32 k) {
+ return (ConfigValues::ValueType)((k >> KP_TYPE_SHIFT) & KP_TYPE_MASK);
+}
+
+ConfigValues::ConfigValues(Uint32 sz, Uint32 dsz){
+ m_size = sz;
+ m_dataSize = dsz;
+ m_stringCount = 0;
+ m_int64Count = 0;
+ for(Uint32 i = 0; i<m_size; i++){
+ m_values[i << 1] = CFV_KEY_FREE;
+ }
+}
+
+ConfigValues::~ConfigValues(){
+ for(Uint32 i = 0; i<m_stringCount; i++){
+ free(* getString(i));
+ }
+}
+
+bool
+ConfigValues::ConstIterator::get(Uint32 key, Entry * result) const {
+ Uint32 pos;
+ if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){
+ return false;
+ }
+
+ result->m_key = key;
+ return m_cfg.getByPos(pos, result);
+}
+
+bool
+ConfigValues::getByPos(Uint32 pos, Entry * result) const {
+ assert(pos < (2 * m_size));
+ Uint32 keypart = m_values[pos];
+ Uint32 val = m_values[pos+1];
+
+ switch(::getTypeOf(keypart)){
+ case IntType:
+ case SectionType:
+ result->m_int = val;
+ break;
+ case StringType:
+ result->m_string = * getString(val);
+ break;
+ case Int64Type:
+ result->m_int64 = * get64(val);
+ break;
+ case InvalidType:
+ default:
+ return false;
+ }
+
+ result->m_type = ::getTypeOf(keypart);
+
+ return true;
+}
+
+Uint64 *
+ConfigValues::get64(Uint32 index) const {
+ assert(index < m_int64Count);
+ const Uint32 * data = m_values + (m_size << 1);
+ Uint64 * ptr = (Uint64*)data;
+ ptr += index;
+ return ptr;
+}
+
+char **
+ConfigValues::getString(Uint32 index) const {
+ assert(index < m_stringCount);
+ const Uint32 * data = m_values + (m_size << 1);
+ char * ptr = (char*)data;
+ ptr += m_dataSize;
+ ptr -= (index * sizeof(char *));
+ return (char**)ptr;
+}
+
+bool
+ConfigValues::ConstIterator::openSection(Uint32 key, Uint32 no){
+ Uint32 curr = m_currentSection;
+
+ Entry tmp;
+ if(get(key, &tmp) && tmp.m_type == SectionType){
+ m_currentSection = tmp.m_int;
+ if(get(no, &tmp) && tmp.m_type == IntType){
+ m_currentSection = tmp.m_int;
+ /**
+ * Validate
+ */
+ if(get(CFV_KEY_PARENT, &tmp)){
+ return true;
+ }
+ }
+ }
+
+ m_currentSection = curr;
+ return false;
+}
+
+bool
+ConfigValues::ConstIterator::closeSection() {
+
+ Entry tmp;
+ if(get(CFV_KEY_PARENT, &tmp) && tmp.m_type == IntType){
+ m_currentSection = tmp.m_int;
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ConfigValues::Iterator::set(Uint32 key, Uint32 value){
+ Uint32 pos;
+ if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){
+ return false;
+ }
+
+ if(::getTypeOf(m_cfg.m_values[pos]) != IntType){
+ return false;
+ }
+
+ m_cfg.m_values[pos+1] = value;
+ return true;
+}
+
+bool
+ConfigValues::Iterator::set(Uint32 key, Uint64 value){
+ Uint32 pos;
+ if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){
+ return false;
+ }
+
+ if(::getTypeOf(m_cfg.m_values[pos]) != Int64Type){
+ return false;
+ }
+
+ * m_cfg.get64(m_cfg.m_values[pos+1]) = value;
+ return true;
+}
+
+bool
+ConfigValues::Iterator::set(Uint32 key, const char * value){
+ Uint32 pos;
+ if(!findKey(m_cfg.m_values, m_cfg.m_size, key | m_currentSection, &pos)){
+ return false;
+ }
+
+ if(::getTypeOf(m_cfg.m_values[pos]) != StringType){
+ return false;
+ }
+
+ char ** str = m_cfg.getString(m_cfg.m_values[pos+1]);
+ free(* str);
+ * str = strdup(value ? value : "");
+ return true;
+}
+
+static
+bool
+findKey(const Uint32 * values, Uint32 sz, Uint32 key, Uint32 * _pos){
+ Uint32 pos = hash(key, sz);
+ Uint32 count = 0;
+ while((values[pos] & KP_MASK) != key && count < sz){
+ pos = nextHash(key, sz, pos, ++count);
+ }
+
+ if((values[pos] & KP_MASK)== key){
+ *_pos = pos;
+ return true;
+ }
+ return false;
+}
+
+static
+Uint32
+hash(Uint32 key, Uint32 size){
+ Uint32 tmp = (key >> 16) ^ (key & 0xFFFF);
+ return (((tmp << 16) | tmp) % size) << 1;
+}
+
+static
+Uint32
+nextHash(Uint32 key, Uint32 size, Uint32 pos, Uint32 count){
+ Uint32 p = (pos >> 1);
+ if((key % size) != 0)
+ p += key;
+ else
+ p += 1;
+ return (p % size) << 1;
+}
+
+static
+Uint32
+directory(Uint32 sz){
+ const Uint32 _input = sz;
+ if((sz & 1) == 0)
+ sz ++;
+
+ bool prime = false;
+ while(!prime){
+ prime = true;
+ for(Uint32 n = 3; n*n <= sz; n += 2){
+ if((sz % n) == 0){
+ prime = false;
+ sz += 2;
+ break;
+ }
+ }
+ }
+ DEBUG printf("directory %d -> %d\n", _input, sz);
+ return sz;
+}
+
+ConfigValuesFactory::ConfigValuesFactory(Uint32 keys, Uint32 data){
+ m_sectionCounter = (1 << KP_SECTION_SHIFT);
+ m_freeKeys = directory(keys);
+ m_freeData = (data + 7) & ~7;
+ m_currentSection = 0;
+ m_cfg = create(m_freeKeys, m_freeData);
+}
+
+ConfigValuesFactory::ConfigValuesFactory(ConfigValues * cfg){
+ m_cfg = cfg;
+ m_freeKeys = 0;
+ m_freeData = m_cfg->m_dataSize;
+ m_sectionCounter = (1 << KP_SECTION_SHIFT);
+ m_currentSection = 0;
+ const Uint32 sz = 2 * m_cfg->m_size;
+ for(Uint32 i = 0; i<sz; i += 2){
+ const Uint32 key = m_cfg->m_values[i];
+ if(key == CFV_KEY_FREE){
+ m_freeKeys++;
+ } else {
+ switch(::getTypeOf(key)){
+ case ConfigValues::IntType:
+ case ConfigValues::SectionType:
+ break;
+ case ConfigValues::Int64Type:
+ m_freeData -= sizeof(Uint64);
+ break;
+ case ConfigValues::StringType:
+ m_freeData -= sizeof(char *);
+ break;
+ case ConfigValues::InvalidType:
+ abort();
+ }
+ Uint32 sec = key & (KP_SECTION_MASK << KP_SECTION_SHIFT);
+ m_sectionCounter = (sec > m_sectionCounter ? sec : m_sectionCounter);
+ }
+ }
+}
+
+ConfigValues *
+ConfigValuesFactory::create(Uint32 keys, Uint32 data){
+ Uint32 sz = sizeof(ConfigValues);
+ sz += (2 * keys * sizeof(Uint32));
+ sz += data;
+
+ void * tmp = malloc(sz);
+ return new (tmp) ConfigValues(keys, data);
+}
+
+void
+ConfigValuesFactory::expand(Uint32 fk, Uint32 fs){
+ if(m_freeKeys >= fk && m_freeData >= fs){
+ return ;
+ }
+
+ m_freeKeys = (m_freeKeys >= fk ? m_cfg->m_size : fk + m_cfg->m_size);
+ m_freeData = (m_freeData >= fs ? m_cfg->m_dataSize : fs + m_cfg->m_dataSize);
+ m_freeKeys = directory(m_freeKeys);
+ m_freeData = (m_freeData + 7) & ~7;
+
+ ConfigValues * m_tmp = m_cfg;
+ m_cfg = create(m_freeKeys, m_freeData);
+ put(* m_tmp);
+ m_tmp->~ConfigValues();
+ free(m_tmp);
+}
+
+void
+ConfigValuesFactory::shrink(){
+ if(m_freeKeys == 0 && m_freeData == 0){
+ return ;
+ }
+
+ m_freeKeys = m_cfg->m_size - m_freeKeys;
+ m_freeData = m_cfg->m_dataSize - m_freeData;
+ m_freeKeys = directory(m_freeKeys);
+ m_freeData = (m_freeData + 7) & ~7;
+
+ ConfigValues * m_tmp = m_cfg;
+ m_cfg = create(m_freeKeys, m_freeData);
+ put(* m_tmp);
+ m_tmp->~ConfigValues();
+ free(m_tmp);
+}
+
+bool
+ConfigValuesFactory::openSection(Uint32 key, Uint32 no){
+ ConfigValues::Entry tmp;
+ const Uint32 parent = m_currentSection;
+
+ ConfigValues::ConstIterator iter(* m_cfg);
+ iter.m_currentSection = m_currentSection;
+ if(!iter.get(key, &tmp)){
+
+ tmp.m_key = key;
+ tmp.m_type = ConfigValues::SectionType;
+ tmp.m_int = m_sectionCounter;
+ m_sectionCounter += (1 << KP_SECTION_SHIFT);
+
+ if(!put(tmp)){
+ return false;
+ }
+ }
+
+ if(tmp.m_type != ConfigValues::SectionType){
+ return false;
+ }
+
+ m_currentSection = tmp.m_int;
+
+ tmp.m_key = no;
+ tmp.m_type = ConfigValues::IntType;
+ tmp.m_int = m_sectionCounter;
+ if(!put(tmp)){
+ m_currentSection = parent;
+ return false;
+ }
+ m_sectionCounter += (1 << KP_SECTION_SHIFT);
+
+ m_currentSection = tmp.m_int;
+ tmp.m_type = ConfigValues::IntType;
+ tmp.m_key = CFV_KEY_PARENT;
+ tmp.m_int = parent;
+ if(!put(tmp)){
+ m_currentSection = parent;
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ConfigValuesFactory::closeSection(){
+ ConfigValues::ConstIterator iter(* m_cfg);
+ iter.m_currentSection = m_currentSection;
+ const bool b = iter.closeSection();
+ m_currentSection = iter.m_currentSection;
+ return b;
+}
+
+bool
+ConfigValuesFactory::put(const ConfigValues::Entry & entry){
+
+ if(m_freeKeys == 0 ||
+ (entry.m_type == ConfigValues::StringType && m_freeData < sizeof(char *))
+ || (entry.m_type == ConfigValues::Int64Type && m_freeData < 8 )){
+
+ DEBUG ndbout_c("m_freeKeys = %d, m_freeData = %d -> expand",
+ m_freeKeys, m_freeData);
+
+ expand(31, 20);
+ }
+
+ const Uint32 tmp = entry.m_key | m_currentSection;
+ const Uint32 sz = m_cfg->m_size;
+ Uint32 pos = hash(tmp, sz);
+ Uint32 count = 0;
+ Uint32 val = m_cfg->m_values[pos];
+
+ while((val & KP_MASK) != tmp && val != CFV_KEY_FREE && count < sz){
+ pos = nextHash(tmp, sz, pos, ++count);
+ val = m_cfg->m_values[pos];
+ }
+
+ if((val & KP_MASK) == tmp){
+ DEBUG ndbout_c("key %x already found at pos: %d", tmp, pos);
+ return false;
+ }
+
+ if(count >= sz){
+ pos = hash(tmp, sz);
+ count = 0;
+ Uint32 val = m_cfg->m_values[pos];
+
+ printf("key: %d, (key %% size): %d\n", entry.m_key, (entry.m_key % sz));
+ printf("pos: %d", pos);
+ while((val & KP_MASK) != tmp && val != CFV_KEY_FREE && count < sz){
+ pos = nextHash(tmp, sz, pos, ++count);
+ val = m_cfg->m_values[pos];
+ printf(" %d", pos);
+ }
+ printf("\n");
+
+ abort();
+ printf("Full\n");
+ return false;
+ }
+
+ assert(pos < (sz << 1));
+
+ Uint32 key = tmp;
+ key |= (entry.m_type << KP_TYPE_SHIFT);
+ m_cfg->m_values[pos] = key;
+ switch(entry.m_type){
+ case ConfigValues::IntType:
+ case ConfigValues::SectionType:
+ m_cfg->m_values[pos+1] = entry.m_int;
+ m_freeKeys--;
+ DEBUG printf("Putting at: %d(%d) (loop = %d) key: %d value: %d\n",
+ pos, sz, count,
+ (key >> KP_KEYVAL_SHIFT) & KP_KEYVAL_MASK,
+ entry.m_int);
+ return true;
+ case ConfigValues::StringType:{
+ Uint32 index = m_cfg->m_stringCount++;
+ m_cfg->m_values[pos+1] = index;
+ char ** ref = m_cfg->getString(index);
+ * ref = strdup(entry.m_string ? entry.m_string : "");
+ m_freeKeys--;
+ m_freeData -= sizeof(char *);
+ DEBUG printf("Putting at: %d(%d) (loop = %d) key: %d value(%d): %s\n",
+ pos, sz, count,
+ (key >> KP_KEYVAL_SHIFT) & KP_KEYVAL_MASK,
+ index,
+ entry.m_string);
+ return true;
+ }
+ case ConfigValues::Int64Type:{
+ Uint32 index = m_cfg->m_int64Count++;
+ m_cfg->m_values[pos+1] = index;
+ * m_cfg->get64(index) = entry.m_int64;
+ m_freeKeys--;
+ m_freeData -= 8;
+ DEBUG printf("Putting at: %d(%d) (loop = %d) key: %d value64(%d): %lld\n",
+ pos, sz, count,
+ (key >> KP_KEYVAL_SHIFT) & KP_KEYVAL_MASK,
+ index,
+ entry.m_int64);
+ return true;
+ }
+ case ConfigValues::InvalidType:
+ default:
+ return false;
+ }
+ return false;
+}
+
+void
+ConfigValuesFactory::put(const ConfigValues & cfg){
+
+ Uint32 curr = m_currentSection;
+ m_currentSection = 0;
+
+ ConfigValues::Entry tmp;
+ for(Uint32 i = 0; i < 2 * cfg.m_size; i += 2){
+ if(cfg.m_values[i] != CFV_KEY_FREE){
+ tmp.m_key = cfg.m_values[i];
+ cfg.getByPos(i, &tmp);
+ put(tmp);
+ }
+ }
+
+ m_currentSection = curr;
+}
+
+ConfigValues *
+ConfigValuesFactory::extractCurrentSection(const ConfigValues::ConstIterator & cfg){
+ ConfigValuesFactory * fac = new ConfigValuesFactory(20, 20);
+ Uint32 curr = cfg.m_currentSection;
+
+ ConfigValues::Entry tmp;
+ for(Uint32 i = 0; i < 2 * cfg.m_cfg.m_size; i += 2){
+ Uint32 keypart = cfg.m_cfg.m_values[i];
+ const Uint32 sec = keypart & (KP_SECTION_MASK << KP_SECTION_SHIFT);
+ const Uint32 key = keypart & KP_KEYVAL_MASK;
+ if(sec == curr && key != CFV_KEY_PARENT){
+ tmp.m_key = cfg.m_cfg.m_values[i];
+ cfg.m_cfg.getByPos(i, &tmp);
+ tmp.m_key = key;
+ fac->put(tmp);
+ }
+ }
+
+ ConfigValues * ret = fac->m_cfg;
+ delete fac;
+ return ret;
+}
+
+ConfigValues *
+ConfigValuesFactory::getConfigValues(){
+ ConfigValues * ret = m_cfg;
+ m_cfg = create(10, 10);
+ return ret;
+}
+
+static int
+mod4(unsigned int i){
+ int res = i + (4 - (i % 4));
+ return res;
+}
+
+Uint32
+ConfigValues::getPackedSize() const {
+
+ Uint32 size = 0;
+ for(Uint32 i = 0; i < 2 * m_size; i += 2){
+ Uint32 key = m_values[i];
+ if(key != CFV_KEY_FREE){
+ switch(::getTypeOf(key)){
+ case IntType:
+ case SectionType:
+ size += 8;
+ break;
+ case Int64Type:
+ size += 12;
+ break;
+ case StringType:
+ size += 8; // key + len
+ size += mod4(strlen(* getString(m_values[i+1])) + 1);
+ break;
+ case InvalidType:
+ default:
+ abort();
+ }
+ }
+ }
+
+ return size + sizeof(Magic) + 4; // checksum also
+}
+
+Uint32
+ConfigValues::pack(void * _dst, Uint32 _len) const {
+ Uint32 i;
+ char * dst = (char*)_dst;
+ memcpy(dst, Magic, sizeof(Magic)); dst += sizeof(Magic);
+
+ for(i = 0; i < 2 * m_size; i += 2){
+ Uint32 key = m_values[i];
+ Uint32 val = m_values[i+1];
+ if(key != CFV_KEY_FREE){
+ switch(::getTypeOf(key)){
+ case IntType:
+ case SectionType:
+ * (Uint32*)dst = htonl(key); dst += 4;
+ * (Uint32*)dst = htonl(val); dst += 4;
+ break;
+ case Int64Type:{
+ Uint64 i64 = * get64(val);
+ Uint32 hi = (i64 >> 32);
+ Uint32 lo = (i64 & 0xFFFFFFFF);
+ * (Uint32*)dst = htonl(key); dst += 4;
+ * (Uint32*)dst = htonl(hi); dst += 4;
+ * (Uint32*)dst = htonl(lo); dst += 4;
+ }
+ break;
+ case StringType:{
+ const char * str = * getString(val);
+ Uint32 len = strlen(str) + 1;
+ * (Uint32*)dst = htonl(key); dst += 4;
+ * (Uint32*)dst = htonl(len); dst += 4;
+ memcpy(dst, str, len);
+ memset(dst+len, 0, mod4(len) - len);
+ dst += mod4(len);
+ }
+ break;
+ case InvalidType:
+ default:
+ abort();
+ }
+ }
+ }
+
+ const Uint32 * sum = (Uint32*)_dst;
+ const Uint32 len = ((Uint32*)dst) - sum;
+ Uint32 chk = 0;
+ for(i = 0; i<len; i++){
+ chk ^= htonl(sum[i]);
+ }
+
+ * (Uint32*)dst = htonl(chk); dst += 4;
+ return 4 * (len + 1);
+}
+
+bool
+ConfigValuesFactory::unpack(const void * _src, Uint32 len){
+
+ if(len < sizeof(Magic) + 4){
+ DEBUG abort();
+ return false;
+ }
+
+ if(memcmp(_src, Magic, sizeof(Magic)) != 0){
+ DEBUG abort();
+ return false;
+ }
+
+ const char * src = (const char *)_src;
+
+ {
+ Uint32 len32 = (len >> 2);
+ const Uint32 * tmp = (const Uint32*)_src;
+ Uint32 chk = 0;
+ for(Uint32 i = 0; (i+1)<len32; i++){
+ chk ^= ntohl(tmp[i]);
+ }
+
+ if(chk != ntohl(tmp[len32-1])){
+ DEBUG abort();
+ return false;
+ }
+ }
+
+ const char * end = src + len - 4;
+ src += sizeof(Magic);
+
+ ConfigValues::Entry entry;
+ while(end - src > 4){
+ Uint32 tmp = ntohl(* (const Uint32 *)src); src += 4;
+ entry.m_key = tmp & KP_MASK;
+ entry.m_type = ::getTypeOf(tmp);
+ switch(entry.m_type){
+ case ConfigValues::IntType:
+ case ConfigValues::SectionType:
+ entry.m_int = ntohl(* (const Uint32 *)src); src += 4;
+ break;
+ case ConfigValues::Int64Type:{
+ Uint64 hi = ntohl(* (const Uint32 *)src); src += 4;
+ Uint64 lo = ntohl(* (const Uint32 *)src); src += 4;
+ entry.m_int64 = (hi <<32) | lo;
+ }
+ break;
+ case ConfigValues::StringType:{
+ Uint32 s_len = ntohl(* (const Uint32 *)src); src += 4;
+ size_t s_len2 = strlen((const char*)src);
+ if(s_len2 + 1 != s_len){
+ DEBUG abort();
+ return false;
+ }
+
+ entry.m_string = (const char*)src; src+= mod4(s_len);
+ }
+ break;
+ case ConfigValues::InvalidType:
+ default:
+ DEBUG abort();
+ return false;
+ }
+ if(!put(entry)){
+ DEBUG abort();
+ return false;
+ }
+ }
+ if(src != end){
+ DEBUG abort();
+ return false;
+ }
+ return true;
+}
+
+#ifdef __TEST_CV_HASH_HPP
+
+int
+main(void){
+ srand(time(0));
+ for(int t = 0; t<100; t++){
+ const size_t len = directory(rand() % 1000);
+
+ printf("size = %d\n", len);
+ unsigned * buf = new unsigned[len];
+ for(size_t key = 0; key<len; key++){
+ Uint32 p = hash(key, len);
+ for(size_t j = 0; j<len; j++){
+ buf[j] = p;
+ p = nextHash(key, len, p, j+1);
+ }
+
+ for(size_t j = 0; j<len; j++){
+ Uint32 pos = buf[j];
+ int unique = 0;
+ for(size_t k = j + 1; k<len; k++){
+ if(pos == buf[k]){
+ if(unique > 0)
+ printf("size=%d key=%d pos(%d)=%d buf[%d]=%d\n", len, key, j, pos, k, buf[k]);
+ unique ++;
+ }
+ }
+ if(unique > 1){
+ printf("key = %d size = %d not uniqe!!\n", key, len);
+ for(size_t k = 0; k<len; k++){
+ printf("%d ", buf[k]);
+ }
+ printf("\n");
+ }
+ }
+ }
+ delete[] buf;
+ }
+ return 0;
+}
+
+#endif
diff --git a/storage/ndb/src/common/util/File.cpp b/storage/ndb/src/common/util/File.cpp
new file mode 100644
index 00000000000..937b8c0fa59
--- /dev/null
+++ b/storage/ndb/src/common/util/File.cpp
@@ -0,0 +1,205 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+
+#include <File.hpp>
+
+#include <NdbOut.hpp>
+#include <my_dir.h>
+
+//
+// PUBLIC
+//
+
+bool
+File_class::exists(const char* aFileName)
+{
+ bool rc = true;
+#ifdef USE_MY_STAT_STRUCT
+ struct my_stat stmp;
+#else
+ struct stat stmp;
+#endif
+ if (my_stat(aFileName, &stmp, MYF(0)) != 0)
+ {
+ rc = false;
+ }
+
+ /*
+ File f;
+ if (!f.open(aFileName, "r"))
+ {
+ rc = (errno == ENOENT ? false : true);
+ }
+ else
+ {
+ f.close();
+ }
+ */
+ return rc;
+}
+
+long
+File_class::size(FILE* f)
+{
+ long cur_pos = 0, length = 0;
+
+ cur_pos = ::ftell(f);
+ ::fseek(f, 0, SEEK_END);
+ length = ::ftell(f);
+ ::fseek(f, cur_pos, SEEK_SET); // restore original position
+
+ return length;
+}
+
+bool
+File_class::rename(const char* currFileName, const char* newFileName)
+{
+ return ::rename(currFileName, newFileName) == 0 ? true : false;
+}
+bool
+File_class::remove(const char* aFileName)
+{
+ return ::remove(aFileName) == 0 ? true : false;
+}
+
+File_class::File_class() :
+ m_file(NULL),
+ m_fileMode("r")
+{
+}
+
+File_class::File_class(const char* aFileName, const char* mode) :
+ m_file(NULL),
+ m_fileMode(mode)
+{
+ BaseString::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName);
+}
+
+bool
+File_class::open()
+{
+ return open(m_fileName, m_fileMode);
+}
+
+bool
+File_class::open(const char* aFileName, const char* mode)
+{
+ if(m_fileName != aFileName){
+ /**
+ * Only copy if it's not the same string
+ */
+ BaseString::snprintf(m_fileName, MAX_FILE_NAME_SIZE, aFileName);
+ }
+ m_fileMode = mode;
+ bool rc = true;
+ if ((m_file = ::fopen(m_fileName, m_fileMode))== NULL)
+ {
+ rc = false;
+ }
+
+ return rc;
+}
+File_class::~File_class()
+{
+ close();
+}
+
+bool
+File_class::remove()
+{
+ // Close the file first!
+ close();
+ return File_class::remove(m_fileName);
+}
+
+bool
+File_class::close()
+{
+ bool rc = true;
+ if (m_file != NULL)
+ {
+ ::fflush(m_file);
+ rc = (::fclose(m_file) == 0 ? true : false);
+ m_file = NULL; // Try again?
+ }
+
+ return rc;
+}
+
+int
+File_class::read(void* buf, size_t itemSize, size_t nitems) const
+{
+ return ::fread(buf, itemSize, nitems, m_file);
+}
+
+int
+File_class::readChar(char* buf, long start, long length) const
+{
+ return ::fread((void*)&buf[start], 1, length, m_file);
+}
+
+int
+File_class::readChar(char* buf)
+{
+ return readChar(buf, 0, strlen(buf));
+}
+
+int
+File_class::write(const void* buf, size_t size, size_t nitems)
+{
+ return ::fwrite(buf, size, nitems, m_file);
+}
+
+int
+File_class::writeChar(const char* buf, long start, long length)
+{
+ return ::fwrite((const void*)&buf[start], sizeof(char), length, m_file);
+}
+
+int
+File_class::writeChar(const char* buf)
+{
+ return writeChar(buf, 0, ::strlen(buf));
+}
+
+long
+File_class::size() const
+{
+ return File_class::size(m_file);
+}
+
+const char*
+File_class::getName() const
+{
+ return m_fileName;
+}
+
+int
+File_class::flush() const
+{
+#if defined NDB_OSE || defined NDB_SOFTOSE
+ ::fflush(m_file);
+ return ::fsync(::fileno(m_file));
+#else
+ return 0;
+#endif
+}
+
+//
+// PRIVATE
+//
diff --git a/storage/ndb/src/common/util/InputStream.cpp b/storage/ndb/src/common/util/InputStream.cpp
new file mode 100644
index 00000000000..410e9a70e9c
--- /dev/null
+++ b/storage/ndb/src/common/util/InputStream.cpp
@@ -0,0 +1,61 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+
+#include "InputStream.hpp"
+#include <socket_io.h>
+
+FileInputStream Stdin(stdin);
+
+FileInputStream::FileInputStream(FILE * file)
+ : f(file) {
+}
+
+char*
+FileInputStream::gets(char * buf, int bufLen){
+ if(!feof(f)){
+ return fgets(buf, bufLen, f);
+ }
+ return 0;
+}
+
+SocketInputStream::SocketInputStream(NDB_SOCKET_TYPE socket,
+ unsigned readTimeout)
+ : m_socket(socket) {
+ m_timeout = readTimeout;
+}
+
+char*
+SocketInputStream::gets(char * buf, int bufLen) {
+ buf[0] = 77;
+ assert(bufLen >= 2);
+ int res = readln_socket(m_socket, m_timeout, buf, bufLen - 1);
+ if(res == -1)
+ return 0;
+ if(res == 0 && buf[0] == 77){ // select return 0
+ buf[0] = 0;
+ } else if(res == 0 && buf[0] == 0){ // only newline
+ buf[0] = '\n';
+ buf[1] = 0;
+ } else {
+ int len = strlen(buf);
+ buf[len + 1] = '\0';
+ buf[len] = '\n';
+ }
+ return buf;
+}
diff --git a/storage/ndb/src/common/util/Makefile.am b/storage/ndb/src/common/util/Makefile.am
new file mode 100644
index 00000000000..2719d14ee92
--- /dev/null
+++ b/storage/ndb/src/common/util/Makefile.am
@@ -0,0 +1,49 @@
+
+noinst_LTLIBRARIES = libgeneral.la
+
+libgeneral_la_SOURCES = \
+ File.cpp md5_hash.cpp Properties.cpp socket_io.cpp \
+ SimpleProperties.cpp Parser.cpp InputStream.cpp \
+ SocketServer.cpp SocketClient.cpp SocketAuthenticator.cpp\
+ OutputStream.cpp NdbOut.cpp BaseString.cpp Base64.cpp \
+ NdbSqlUtil.cpp new.cpp \
+ uucode.c random.c version.c \
+ strdup.c \
+ ConfigValues.cpp ndb_init.c basestring_vsnprintf.c \
+ Bitmask.cpp
+
+EXTRA_PROGRAMS = testBitmask
+testBitmask_SOURCES = testBitmask.cpp
+testBitmask_LDFLAGS = @ndb_bin_am_ldflags@ \
+ $(top_builddir)/ndb/src/libndbclient.la \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/strings/libmystrings.a
+
+testBitmask.cpp : Bitmask.cpp
+ rm -f testBitmask.cpp
+ @LN_CP_F@ Bitmask.cpp testBitmask.cpp
+
+testBitmask.o: $(testBitmask_SOURCES)
+ $(CXXCOMPILE) -c $(INCLUDES) -D__TEST_BITMASK__ $<
+
+
+include $(top_srcdir)/ndb/config/common.mk.am
+include $(top_srcdir)/ndb/config/type_util.mk.am
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
+
+windoze-dsp: libgeneral.dsp
+
+libgeneral.dsp: Makefile \
+ $(top_srcdir)/ndb/config/win-lib.am \
+ $(top_srcdir)/ndb/config/win-name \
+ $(top_srcdir)/ndb/config/win-includes \
+ $(top_srcdir)/ndb/config/win-sources \
+ $(top_srcdir)/ndb/config/win-libraries
+ cat $(top_srcdir)/ndb/config/win-lib.am > $@
+ @$(top_srcdir)/ndb/config/win-name $@ $(noinst_LTLIBRARIES)
+ @$(top_srcdir)/ndb/config/win-includes $@ $(INCLUDES)
+ @$(top_srcdir)/ndb/config/win-sources $@ $(libgeneral_la_SOURCES)
+ @$(top_srcdir)/ndb/config/win-libraries $@ LIB $(LDADD)
diff --git a/storage/ndb/src/common/util/NdbErrHnd.cpp b/storage/ndb/src/common/util/NdbErrHnd.cpp
new file mode 100644
index 00000000000..38a67f29853
--- /dev/null
+++ b/storage/ndb/src/common/util/NdbErrHnd.cpp
@@ -0,0 +1,492 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#if defined NDB_OSE || defined NDB_SOFTOSE
+
+#include <NdbOut.hpp>
+#include <ndb_types.h>
+
+#include "ose.h"
+#include "ose_err.h"
+#include "osetypes.h"
+
+
+#define BUFSIZE 100
+
+typedef struct {
+ char header1[BUFSIZE];
+ char header2[BUFSIZE];
+ char error_code_line[BUFSIZE];
+ char subcode_line[BUFSIZE];
+ char product_line[BUFSIZE];
+ char header_file_line[BUFSIZE];
+ char extra_line[BUFSIZE];
+ char user_called_line[BUFSIZE];
+ char current_process_id_line[BUFSIZE];
+ char current_process_name_line[BUFSIZE];
+ char file_line[BUFSIZE];
+ char line_line[BUFSIZE];
+ char err_hnd_file[BUFSIZE];
+} Error_message;
+
+char assert_line[BUFSIZE];
+char unknown_signal_line[BUFSIZE];
+char signal_number_line[BUFSIZE];
+char sender_line[BUFSIZE];
+char receiver_line[BUFSIZE];
+
+extern "C" OSBOOLEAN ndb_err_hnd(bool user_called,
+ Uint32 error_code,
+ Uint32 extra)
+{
+ static Error_message error_message;
+ bool error_handled;
+ Uint32 subcode;
+
+ char* subcode_mnemonic;
+ char* product_name;
+ char* file_name;
+
+ /*The subcode (bit 16 - 30) is extracted from error_code */
+ subcode = (error_code & 0x7fff0000) >> 16;
+
+ if (user_called) {
+ switch (subcode) {
+ case 0x0050 :
+ subcode_mnemonic= "OSE_PRH_PLS";
+ product_name= "Program Loader";
+ file_name = "prherr.h";
+ break;
+ case 0x0051 :
+ subcode_mnemonic = "OSE_PRH_START_PRH";
+ product_name= "start_prh";
+ file_name= " start_prh.c";
+ break;
+ case 0x0052 :
+ subcode_mnemonic= "OSE_PRH_ASF";
+ product_name= "Archive Server";
+ file_name = "prherr.h";
+ break;
+ case 0x0058 :
+ case 0x4058 :
+ case 0x3fff :
+ case 0x8058 :
+ subcode_mnemonic= "OSE_MMS_EBASE";
+ product_name= "MMS";
+ file_name= "mms_err.h";
+ break;
+ /*Link Handler G3***************************************/
+ case 0x0060 :
+ case 0x8060 :
+ subcode_mnemonic= "OSE_GLH_EBASE";
+ product_name= "General Link Handler";
+ file_name= "glherr.h";
+ break;
+ case 0x0064 :
+ case 0x8064 :
+ subcode_mnemonic= "OSE_GPL_EBASE";
+ product_name= "General Protocol Link Handler";
+ file_name= "gplerr.h";
+ break;
+ case 0x0066 :
+ case 0x8066 :
+ subcode_mnemonic= "OSE_UDPPDR_EBASE";
+ product_name= "UDP driver for GPL";
+ file_name= "udppdrerr.h";
+ break;
+ case 0x0067 :
+ case 0x8067 :
+ subcode_mnemonic= "OSE_SERPDR_EBASE";
+ product_name= "Serial driver for GPL";
+ file_name= "serpdrerr.h";
+ break;
+ case 0x0068 :
+ case 0x8068 :
+ subcode_mnemonic= "OSE_ETHPDR_EBASE";
+ product_name= "Ethernet driver for GPL";
+ file_name= "ethpdrerr.h";
+ break;
+ /*Link handler G4***************************************/
+ case 0x0061 :
+ subcode_mnemonic= "OSE_OTL_EBASE";
+ product_name= "OSE Transport Layer";
+ file_name= "otlerr.h";
+ break;
+ case 0x0062 :
+ subcode_mnemonic= "OSE_LALUDP_EBASE";
+ product_name= "Link Adaption Layer for UDP";
+ file_name= "header file unknown";
+ break;
+ /*Internet Utilities************************************/
+ case 0x0069 :
+ subcode_mnemonic= "OSE_TFTPD";
+ product_name= "TFTP server";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x006a :
+ subcode_mnemonic= "OSE_TELUDPD";
+ product_name= "TELNET/UDP server";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x006b :
+ subcode_mnemonic= "OSE_FTPD";
+ product_name= "FTP server";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x006c :
+ subcode_mnemonic= "OSE_TELNETD";
+ product_name= "TELNET server";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x006d :
+ subcode_mnemonic= "OSE_SURFER";
+ product_name= "OSE System Surfer";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x006e :
+ subcode_mnemonic= "OSE_BOOTP";
+ product_name= "BOOTP client";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x006f :
+ switch((error_code & 0x0000f000)){
+ case 0x00000000 :
+ subcode_mnemonic= "OSE_RES";
+ product_name= "DNS resolver";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x00001000 :
+ subcode_mnemonic= "OSE_DHCPC";
+ product_name= "DHCP client";
+ file_name= "inetutilerr.h";
+ break;
+ case 0x00002000 :
+ subcode_mnemonic= "OSE_FTP";
+ product_name= "FTP client";
+ file_name= "inetutilerr.h";
+ break;
+ default :
+ subcode_mnemonic= "Unknown error";
+ product_name= "unknown product";
+ file_name = "header file unknown";
+ break;
+ }
+ break;
+ case 0x00c2 :
+ subcode_mnemonic= "OSE_DNS";
+ product_name= "DNS server";
+ file_name= "dns_err.h";
+ break;
+ /*INET**************************/
+ case 0x0070 :
+ subcode_mnemonic= "INET_ERRBASE";
+ product_name= "Internet Protocols (INET)";
+ file_name= "ineterr.h";
+ break;
+ case 0x0071 :
+ subcode_mnemonic= "WEBS_ERRBASE";
+ product_name= "Web Server (WEBS)";
+ file_name= "webserr.h";
+ break;
+ case 0x0072 :
+ subcode_mnemonic= "SNMP";
+ product_name= "SNMP";
+ file_name= "header file unknown";
+ break;
+ case 0x0073 :
+ subcode_mnemonic= "STP_BRIDGE";
+ product_name= "STP bridge";
+ file_name= "header file unknown";
+ break;
+ case 0x0200 :
+ case 0x0201 :
+ case 0x0202 :
+ case 0x0203 :
+ case 0x0204 :
+ case 0x0205 :
+ case 0x0206 :
+ case 0x0207 :
+ case 0x0208 :
+ case 0x0209 :
+ case 0x020a :
+ case 0x020b :
+ case 0x020c :
+ case 0x020d :
+ case 0x020e :
+ case 0x020f :
+ subcode_mnemonic = "INETINIT_ERR_BASE";
+ product_name = "INET";
+ file_name = "startinet.c";
+ break;
+ /*Miscellanous******************************************/
+ case 0x0082 :
+ subcode_mnemonic= "OSE_HEAP_EBASE";
+ product_name= "Heap Manager";
+ file_name= "heap_err.h";
+ break;
+ case 0x0088 :
+ subcode_mnemonic= "OSE_BSP";
+ product_name= "Board Support Package";
+ file_name= "bsperr.h";
+ break;
+ case 0x008a :
+ subcode_mnemonic= "OSE_TOSV_EBASE";
+ product_name= "Time Out Server";
+ file_name= "tosverr.h";
+ break;
+ case 0x008b :
+ subcode_mnemonic= "OSE_RTC_EBASE";
+ product_name= "Real Time Clock";
+ file_name= "rtcerr.h";
+ break;
+ case 0x008d :
+ case 0x808d :
+ subcode_mnemonic= "OSENS_ERR_BASE";
+ product_name= "Name Server";
+ file_name= "osens_err.h";
+ break;
+ case 0x008e :
+ subcode_mnemonic= "PMD_ERR_BASE";
+ product_name= "Post Mortem Dump";
+ file_name= "pmderr.h";
+ break;
+ /*Embedded File System***********************************/
+ case 0x0090 :
+ subcode_mnemonic= "OSE_EFS_COMMON";
+ product_name= "EFS common";
+ file_name= "efs_err.h";
+ break;
+ case 0x0091 :
+ subcode_mnemonic= "OSE_EFS_FLIB";
+ product_name= "EFS function library";
+ file_name= "efs_err.h";
+ break;
+ case 0x0092 :
+ subcode_mnemonic= "OSE_EFS_SERDD";
+ product_name= "EFS serdd";
+ file_name= "efs_err.h";
+ break;
+ case 0x0093 :
+ subcode_mnemonic= "OSE_EFS_SHELL";
+ product_name= "OSE shell";
+ file_name= "efs_err.h";
+ break;
+ case 0x0094 :
+ subcode_mnemonic= "OSE_EFS_STARTEFS";
+ product_name= "EFS startefs.c";
+ file_name= "efs_err.h";
+ break;
+ /*Debugger related***************************************/
+ case 0x00a0 :
+ subcode_mnemonic= "DBGSERVER_ERR_BASE";
+ product_name= "Debug server for Illuminator";
+ file_name= "degservererr.h";
+ break;
+ case 0x00b2 :
+ subcode_mnemonic= "OSE_MDM";
+ product_name= "Multi INDRT monitor";
+ file_name= "header file unknown";
+ break;
+ /*Miscellanous*******************************************/
+ case 0x00c0 :
+ subcode_mnemonic= "OSE_POTS_EBASE";
+ product_name= "POTS tutorial example";
+ file_name= "pots_err.h";
+ break;
+ case 0x00c1 :
+ subcode_mnemonic= "OSE_PTH_ECODE_BASE";
+ product_name= "Pthreads";
+ file_name= "pthread_err.h";
+ break;
+ case 0x00c3 :
+ subcode_mnemonic= "OSE_NTP_EBASE";
+ product_name= "OSE NTP/SNTP";
+ file_name= "ntp_err.h";
+ break;
+ case 0x00c4 :
+ subcode_mnemonic= "TRILLIUM_BASE";
+ product_name= "Trillium OSE port";
+ file_name= "sk_ss.c";
+ break;
+ case 0x00c5 :
+ subcode_mnemonic= "OSE_OSECPP_EBASE";
+ product_name= "C++ Support with libosecpp.a";
+ file_name= "cpp_err.h";
+ break;
+ case 0x00c6 :
+ subcode_mnemonic= "OSE_RIP_ERR_BASE";
+ product_name= "OSE RIP";
+ file_name= "oserip.h";
+ break;
+ /*Unknown error_code*************************************/
+ default :
+ subcode_mnemonic= "Unknown error";
+ product_name= "unknown product";
+ file_name = "header file unknown";
+ break;
+ }
+ } else {
+ /* user_called = 0, i.e. reported by the kernel */
+ subcode_mnemonic= "OSE_KRN";
+ product_name= "Kernel";
+ file_name = "ose_err.h";
+ }
+
+ BaseString::snprintf(error_message.header1,
+ BUFSIZE,
+ "This is the OSE Example System Error handler\r\n");
+
+ BaseString::snprintf(error_message.err_hnd_file,
+ BUFSIZE,
+ "located in: " __FILE__ "\r\n");
+
+ BaseString::snprintf(error_message.header2,
+ BUFSIZE,
+ "An Error has been reported:\r\n");
+
+ if (user_called == (OSBOOLEAN) 0 ) {
+ BaseString::snprintf(error_message.user_called_line,
+ BUFSIZE,
+ "user_called: 0x%x (Error detected by the kernel)\r\n",
+ user_called);
+ }
+ else {
+ BaseString::snprintf(error_message.user_called_line,
+ BUFSIZE,
+ "user_called: 0x%x (Error detected by an application)\r\n",
+ user_called);
+ }
+
+ BaseString::snprintf(error_message.error_code_line,
+ BUFSIZE,
+ "error code: 0x%08x\r\n",
+ error_code);
+
+ BaseString::snprintf(error_message.subcode_line,
+ BUFSIZE,
+ " subcode: %s (0x%08x)\r\n",
+ subcode_mnemonic,
+ ( subcode << 16));
+
+ BaseString::snprintf(error_message.product_line,
+ BUFSIZE,
+ " product: %s\r\n",
+ product_name);
+
+ BaseString::snprintf(error_message.header_file_line,
+ BUFSIZE,
+ " header file: %s\r\n",
+ file_name);
+
+ BaseString::snprintf(error_message.extra_line,
+ BUFSIZE,
+ "extra: 0x%08x\r\n",
+ extra);
+
+ if (error_code != OSE_ENO_KERN_SPACE || user_called){
+ struct OS_pcb *pcb = get_pcb(current_process());
+ const char *process_name = &pcb->strings[pcb->name];
+
+ BaseString::snprintf(error_message.current_process_id_line,
+ BUFSIZE,
+ "Current Process: 0x%08x\r\n",
+ current_process());
+
+ BaseString::snprintf(error_message.current_process_name_line,
+ BUFSIZE,
+ "Process Name: %s\r\n",
+ process_name);
+
+ BaseString::snprintf(error_message.file_line,
+ BUFSIZE,
+ "File: %s\r\n",
+ &pcb->strings[pcb->file]);
+
+ BaseString::snprintf(error_message.line_line,
+ BUFSIZE,
+ "Line: %d\r\n",
+ pcb->line);
+
+ free_buf((union SIGNAL **)&pcb);
+ }
+
+ if ( !(((error_code & OSE_EFATAL_MASK) != 0) && (user_called == 0))){
+ /* If the error is reported by the kernel and the fatal flag is set,
+ * dbgprintf can't be trusted */
+ ndbout << error_message.header1;
+ ndbout << error_message.err_hnd_file;
+ ndbout << error_message.header2;
+ ndbout << error_message.user_called_line;
+ ndbout << error_message.error_code_line;
+ ndbout << error_message.subcode_line;
+ ndbout << error_message.product_line;
+ ndbout << error_message.header_file_line;
+ ndbout << error_message.extra_line;
+ ndbout << error_message.current_process_id_line;
+ ndbout << error_message.current_process_name_line;
+ ndbout << error_message.file_line;
+ ndbout << error_message.line_line;
+ ndbout << endl;
+ }
+
+ if(user_called){
+ switch (error_code) {
+ /* Check for assertion failure (see oseassert.h and assert.c). */
+ case (OSERRCODE) 0xffffffff:
+ {
+ if(extra != 0){
+ char *expr = ((char **)extra)[0];
+ char *file = ((char **)extra)[1];
+ unsigned line = ((unsigned *)extra)[2];
+ BaseString::snprintf(assert_line, BUFSIZE, "Assertion Failed: %s:%u: %s\r\n", file, line, expr);
+ ndbout << assert_line;
+ }
+ }
+ /* Check for unknown signal */
+ case (OSERRCODE) 0xfffffffe:
+ {
+ union SIGNAL *sig = (union SIGNAL *)extra;
+ SIGSELECT signo = *(SIGSELECT*)sig;
+ PROCESS rcv_ = current_process();
+ PROCESS snd_ = sender(&sig);
+ struct OS_pcb *rcv = get_pcb(rcv_);
+ const char *rcv_name = &rcv->strings[rcv->name];
+ struct OS_pcb *snd = get_pcb(snd_);
+ const char *snd_name = &snd->strings[snd->name];
+ BaseString::snprintf(unknown_signal_line, BUFSIZE,
+ "Unknown Signal Received\r\n");
+ BaseString::snprintf(unknown_signal_line, BUFSIZE,
+ "Signal Number: 0x%08lx\r\n", signo);
+ BaseString::snprintf(unknown_signal_line, BUFSIZE,
+ "Sending Process: 0x%08lx (%s))\r\n", snd_, snd_name);
+ BaseString::snprintf(unknown_signal_line, BUFSIZE,
+ "Receiving Process: 0x%08lx (%s))\r\n", rcv_, rcv_name);
+ free_buf((union SIGNAL **)&rcv);
+ free_buf((union SIGNAL **)&snd); }
+ ndbout << unknown_signal_line;
+ ndbout << signal_number_line;
+ ndbout << sender_line;
+ ndbout << receiver_line;
+ } /* switch */
+ } /* if */
+
+ /* Zero means the error has not been fixed by the error handler. */
+ error_handled = 0;
+ return error_handled;
+}
+
+#endif
diff --git a/storage/ndb/src/common/util/NdbOut.cpp b/storage/ndb/src/common/util/NdbOut.cpp
new file mode 100644
index 00000000000..e20119a7987
--- /dev/null
+++ b/storage/ndb/src/common/util/NdbOut.cpp
@@ -0,0 +1,173 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+
+#include <NdbOut.hpp>
+#include <OutputStream.hpp>
+
+static FileOutputStream ndbouts_fileoutputstream(stdout);
+NdbOut ndbout(ndbouts_fileoutputstream);
+
+static const char * fms[] = {
+ "%d", "0x%02x", // Int8
+ "%u", "0x%02x", // Uint8
+ "%d", "0x%04x", // Int16
+ "%u", "0x%04x", // Uint16
+ "%d", "0x%08x", // Int32
+ "%u", "0x%08x", // Uint32
+ "%lld", "0x%016llx", // Int64
+ "%llu", "0x%016llx" // Uint64
+ "%llu", "0x%016llx" // UintPtr
+};
+
+NdbOut&
+NdbOut::operator<<(Int8 v) { m_out->print(fms[0+isHex],(int)v); return *this;}
+NdbOut&
+NdbOut::operator<<(Uint8 v) { m_out->print(fms[2+isHex],(int)v); return *this;}
+NdbOut&
+NdbOut::operator<<(Int16 v) { m_out->print(fms[4+isHex],(int)v); return *this;}
+NdbOut&
+NdbOut::operator<<(Uint16 v) { m_out->print(fms[6+isHex],(int)v); return *this;}
+NdbOut&
+NdbOut::operator<<(Int32 v) { m_out->print(fms[8+isHex], v); return *this;}
+NdbOut&
+NdbOut::operator<<(Uint32 v) { m_out->print(fms[10+isHex], v); return *this;}
+NdbOut&
+NdbOut::operator<<(Int64 v) { m_out->print(fms[12+isHex], v); return *this;}
+NdbOut&
+NdbOut::operator<<(Uint64 v) { m_out->print(fms[14+isHex], v); return *this;}
+NdbOut&
+NdbOut::operator<<(unsigned long int v) { return *this << (Uint64) v; }
+
+NdbOut&
+NdbOut::operator<<(const char* val){ m_out->print("%s", val ? val : "(null)"); return * this; }
+NdbOut&
+NdbOut::operator<<(const void* val){ m_out->print("%p", val); return * this; }
+NdbOut&
+NdbOut::operator<<(BaseString &val){ return *this << val.c_str(); }
+
+NdbOut&
+NdbOut::operator<<(float val){ m_out->print("%f", (double)val); return * this;}
+NdbOut&
+NdbOut::operator<<(double val){ m_out->print("%f", val); return * this; }
+
+NdbOut& NdbOut::endline()
+{
+ isHex = 0; // Reset hex to normal, if user forgot this
+ m_out->println("");
+ m_out->flush();
+ return *this;
+}
+
+NdbOut& NdbOut::flushline()
+{
+ m_out->flush();
+ return *this;
+}
+
+NdbOut& NdbOut::setHexFormat(int _format)
+{
+ isHex = (_format == 0 ? 0 : 1);
+ return *this;
+}
+
+NdbOut::NdbOut(OutputStream & out)
+ : m_out(& out)
+{
+ isHex = 0;
+}
+
+NdbOut::~NdbOut()
+{
+}
+
+void
+NdbOut::print(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ ndbout << buf;
+ va_end(ap);
+}
+
+void
+NdbOut::println(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ ndbout << buf << endl;
+ va_end(ap);
+}
+
+extern "C"
+void
+ndbout_c(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ ndbout << buf << endl;
+ va_end(ap);
+}
+
+FilteredNdbOut::FilteredNdbOut(OutputStream & out,
+ int threshold, int level)
+ : NdbOut(out) {
+ m_level = level;
+ m_threshold = threshold;
+ m_org = &out;
+ m_null = new NullOutputStream();
+ setLevel(level);
+}
+
+FilteredNdbOut::~FilteredNdbOut(){
+ delete m_null;
+}
+
+void
+FilteredNdbOut::setLevel(int i){
+ m_level = i;
+ if(m_level >= m_threshold){
+ m_out = m_org;
+ } else {
+ m_out = m_null;
+ }
+}
+
+void
+FilteredNdbOut::setThreshold(int i){
+ m_threshold = i;
+ setLevel(m_level);
+}
+
+int
+FilteredNdbOut::getLevel() const {
+ return m_level;
+}
+int
+FilteredNdbOut::getThreshold() const {
+ return m_threshold;
+}
+
diff --git a/storage/ndb/src/common/util/NdbSqlUtil.cpp b/storage/ndb/src/common/util/NdbSqlUtil.cpp
new file mode 100644
index 00000000000..09e150dbacf
--- /dev/null
+++ b/storage/ndb/src/common/util/NdbSqlUtil.cpp
@@ -0,0 +1,1007 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <NdbSqlUtil.hpp>
+#include <NdbOut.hpp>
+#include <my_sys.h>
+
+/*
+ * Data types. The entries must be in the numerical order.
+ */
+
+const NdbSqlUtil::Type
+NdbSqlUtil::m_typeList[] = {
+ { // 0
+ Type::Undefined,
+ NULL,
+ NULL
+ },
+ { // 1
+ Type::Tinyint,
+ cmpTinyint,
+ NULL
+ },
+ { // 2
+ Type::Tinyunsigned,
+ cmpTinyunsigned,
+ NULL
+ },
+ { // 3
+ Type::Smallint,
+ cmpSmallint,
+ NULL
+ },
+ { // 4
+ Type::Smallunsigned,
+ cmpSmallunsigned,
+ NULL
+ },
+ { // 5
+ Type::Mediumint,
+ cmpMediumint,
+ NULL
+ },
+ { // 6
+ Type::Mediumunsigned,
+ cmpMediumunsigned,
+ NULL
+ },
+ { // 7
+ Type::Int,
+ cmpInt,
+ NULL
+ },
+ { // 8
+ Type::Unsigned,
+ cmpUnsigned,
+ NULL
+ },
+ { // 9
+ Type::Bigint,
+ cmpBigint,
+ NULL
+ },
+ { // 10
+ Type::Bigunsigned,
+ cmpBigunsigned,
+ NULL
+ },
+ { // 11
+ Type::Float,
+ cmpFloat,
+ NULL
+ },
+ { // 12
+ Type::Double,
+ cmpDouble,
+ NULL
+ },
+ { // 13
+ Type::Olddecimal,
+ cmpOlddecimal,
+ NULL
+ },
+ { // 14
+ Type::Char,
+ cmpChar,
+ likeChar
+ },
+ { // 15
+ Type::Varchar,
+ cmpVarchar,
+ likeVarchar
+ },
+ { // 16
+ Type::Binary,
+ cmpBinary,
+ likeBinary
+ },
+ { // 17
+ Type::Varbinary,
+ cmpVarbinary,
+ likeVarbinary
+ },
+ { // 18
+ Type::Datetime,
+ cmpDatetime,
+ NULL
+ },
+ { // 19
+ Type::Date,
+ cmpDate,
+ NULL
+ },
+ { // 20
+ Type::Blob,
+ NULL,
+ NULL
+ },
+ { // 21
+ Type::Text,
+ NULL,
+ NULL
+ },
+ { // 22
+ Type::Bit,
+ NULL,
+ NULL
+ },
+ { // 23
+ Type::Longvarchar,
+ cmpLongvarchar,
+ likeLongvarchar
+ },
+ { // 24
+ Type::Longvarbinary,
+ cmpLongvarbinary,
+ likeLongvarbinary
+ },
+ { // 25
+ Type::Time,
+ cmpTime,
+ NULL
+ },
+ { // 26
+ Type::Year,
+ cmpYear,
+ NULL
+ },
+ { // 27
+ Type::Timestamp,
+ cmpTimestamp,
+ NULL
+ },
+ { // 28
+ Type::Olddecimalunsigned,
+ cmpOlddecimalunsigned,
+ NULL
+ },
+ { // 29
+ Type::Decimal,
+ cmpDecimal,
+ NULL
+ },
+ { // 30
+ Type::Decimalunsigned,
+ cmpDecimalunsigned,
+ NULL
+ }
+};
+
+const NdbSqlUtil::Type&
+NdbSqlUtil::getType(Uint32 typeId)
+{
+ if (typeId < sizeof(m_typeList) / sizeof(m_typeList[0]) &&
+ m_typeList[typeId].m_typeId != Type::Undefined) {
+ return m_typeList[typeId];
+ }
+ return m_typeList[Type::Undefined];
+}
+
+const NdbSqlUtil::Type&
+NdbSqlUtil::getTypeBinary(Uint32 typeId)
+{
+ switch (typeId) {
+ case Type::Char:
+ case Type::Varchar:
+ case Type::Binary:
+ case Type::Varbinary:
+ case Type::Longvarchar:
+ case Type::Longvarbinary:
+ typeId = Type::Binary;
+ break;
+ case Type::Text:
+ typeId = Type::Blob;
+ break;
+ default:
+ break;
+ }
+ return getType(typeId);
+}
+
+/*
+ * Comparison functions.
+ */
+
+int
+NdbSqlUtil::cmpTinyint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Int8)) {
+ Int8 v1, v2;
+ memcpy(&v1, p1, sizeof(Int8));
+ memcpy(&v2, p2, sizeof(Int8));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpTinyunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Uint8)) {
+ Uint8 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint8));
+ memcpy(&v2, p2, sizeof(Uint8));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpSmallint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Int16)) {
+ Int16 v1, v2;
+ memcpy(&v1, p1, sizeof(Int16));
+ memcpy(&v2, p2, sizeof(Int16));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpSmallunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Uint16)) {
+ Uint16 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint16));
+ memcpy(&v2, p2, sizeof(Uint16));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpMediumint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= 3) {
+ Int32 v1, v2;
+ v1 = sint3korr((const uchar*)p1);
+ v2 = sint3korr((const uchar*)p2);
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpMediumunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= 3) {
+ Uint32 v1, v2;
+ v1 = uint3korr((const uchar*)p1);
+ v2 = uint3korr((const uchar*)p2);
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpInt(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ 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;
+}
+
+int
+NdbSqlUtil::cmpUnsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Uint32)) {
+ Uint32 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint32));
+ memcpy(&v2, p2, sizeof(Uint32));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpBigint(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool 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;
+}
+
+int
+NdbSqlUtil::cmpBigunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Uint64)) {
+ Uint64 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint64));
+ memcpy(&v2, p2, sizeof(Uint64));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpFloat(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(float)) {
+ float v1, v2;
+ memcpy(&v1, p1, sizeof(float));
+ memcpy(&v2, p2, sizeof(float));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpDouble(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(double)) {
+ double v1, v2;
+ memcpy(&v1, p1, sizeof(double));
+ memcpy(&v2, p2, sizeof(double));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmp_olddecimal(const uchar* s1, const uchar* s2, unsigned n)
+{
+ int sgn = +1;
+ unsigned i = 0;
+ while (i < n) {
+ int c1 = s1[i];
+ int c2 = s2[i];
+ if (c1 == c2) {
+ if (c1 == '-')
+ sgn = -1;
+ } else if (c1 == '-') {
+ return -1;
+ } else if (c2 == '-') {
+ return +1;
+ } else if (c1 < c2) {
+ return -1 * sgn;
+ } else {
+ return +1 * sgn;
+ }
+ i++;
+ }
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpOlddecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (full) {
+ assert(n1 == n2);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ return cmp_olddecimal(v1, v2, n1);
+ }
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpOlddecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (full) {
+ assert(n1 == n2);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ return cmp_olddecimal(v1, v2, n1);
+ }
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpDecimal(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // compare as binary strings
+ unsigned n = (n1 <= n2 ? n1 : n2);
+ int k = memcmp(v1, v2, n);
+ if (k == 0) {
+ k = (full ? n1 : n) - n2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpDecimalunsigned(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // compare as binary strings
+ unsigned n = (n1 <= n2 ? n1 : n2);
+ int k = memcmp(v1, v2, n);
+ if (k == 0) {
+ k = (full ? n1 : n) - n2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ // collation does not work on prefix for some charsets
+ assert(full);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // not const in MySQL
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ // compare with space padding
+ int k = (*cs->coll->strnncollsp)(cs, v1, n1, v2, n2, false);
+ return k < 0 ? -1 : k > 0 ? +1 : 0;
+}
+
+int
+NdbSqlUtil::cmpVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const unsigned lb = 1;
+ // collation does not work on prefix for some charsets
+ assert(full && n1 >= lb && n2 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = *v1;
+ unsigned m2 = *v2;
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ // compare with space padding
+ int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
+ return k < 0 ? -1 : k > 0 ? +1 : 0;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ // compare as binary strings
+ unsigned n = (n1 <= n2 ? n1 : n2);
+ int k = memcmp(v1, v2, n);
+ if (k == 0) {
+ k = (full ? n1 : n) - n2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const unsigned lb = 1;
+ if (n2 >= lb) {
+ assert(n1 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = *v1;
+ unsigned m2 = *v2;
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ // compare as binary strings
+ unsigned m = (m1 <= m2 ? m1 : m2);
+ int k = memcmp(v1 + lb, v2 + lb, m);
+ if (k == 0) {
+ k = (full ? m1 : m) - m2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpDatetime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool 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;
+}
+
+int
+NdbSqlUtil::cmpDate(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+#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;
+ }
+#else
+#ifdef ndb_date_sol9x86_cc_xO3_madness
+ if (n2 >= 3) {
+ 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;
+ }
+#else
+ if (n2 >= 3) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ uint j1 = uint3korr(v1);
+ uint j2 = uint3korr(v2);
+ uint d1 = (j1 & 31);
+ uint d2 = (j2 & 31);
+ j1 = (j1 >> 5);
+ j2 = (j2 >> 5);
+ uint m1 = (j1 & 15);
+ uint m2 = (j2 & 15);
+ j1 = (j1 >> 4);
+ j2 = (j2 >> 4);
+ uint y1 = j1;
+ uint y2 = j2;
+ if (y1 < y2)
+ return -1;
+ if (y1 > y2)
+ return +1;
+ if (m1 < m2)
+ return -1;
+ if (m1 > m2)
+ return +1;
+ if (d1 < d2)
+ return -1;
+ if (d1 > d2)
+ return +1;
+ return 0;
+ }
+#endif
+#endif
+ assert(! full);
+ return CmpUnknown;
+}
+
+// not supported
+int
+NdbSqlUtil::cmpBlob(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ assert(false);
+ return 0;
+}
+
+// not supported
+int
+NdbSqlUtil::cmpText(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ assert(false);
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpTime(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= 3) {
+ 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)
+{
+ assert(false);
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const unsigned lb = 2;
+ // collation does not work on prefix for some charsets
+ assert(full && n1 >= lb && n2 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = uint2korr(v1);
+ unsigned m2 = uint2korr(v2);
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ // compare with space padding
+ int k = (*cs->coll->strnncollsp)(cs, v1 + lb, m1, v2 + lb, m2, false);
+ return k < 0 ? -1 : k > 0 ? +1 : 0;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+}
+
+int
+NdbSqlUtil::cmpLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ const unsigned lb = 2;
+ if (n2 >= lb) {
+ assert(n1 >= lb);
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = uint2korr(v1);
+ unsigned m2 = uint2korr(v2);
+ if (m1 <= n1 - lb && m2 <= n2 - lb) {
+ // compare as binary strings
+ unsigned m = (m1 <= m2 ? m1 : m2);
+ int k = memcmp(v1 + lb, v2 + lb, m);
+ if (k == 0) {
+ k = (full ? m1 : m) - m2;
+ }
+ return k < 0 ? -1 : k > 0 ? +1 : full ? 0 : CmpUnknown;
+ }
+ // treat bad data as NULL
+ if (m1 > n1 - lb && m2 <= n2 - lb)
+ return -1;
+ if (m1 <= n1 - lb && m2 > n2 - lb)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpYear(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Uint8)) {
+ Uint8 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint8));
+ memcpy(&v2, p2, sizeof(Uint8));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+int
+NdbSqlUtil::cmpTimestamp(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2, bool full)
+{
+ if (n2 >= sizeof(Uint32)) {
+ Uint32 v1, v2;
+ memcpy(&v1, p1, sizeof(Uint32));
+ memcpy(&v2, p2, sizeof(Uint32));
+ if (v1 < v2)
+ return -1;
+ if (v1 > v2)
+ return +1;
+ return 0;
+ }
+ assert(! full);
+ return CmpUnknown;
+}
+
+// like
+
+static const int ndb_wild_prefix = '\\';
+static const int ndb_wild_one = '_';
+static const int ndb_wild_many = '%';
+
+int
+NdbSqlUtil::likeChar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ const char* v1 = (const char*)p1;
+ const char* v2 = (const char*)p2;
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ int k = (cs->coll->wildcmp)(cs, v1, v1 + n1, v2, v2 + n2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
+ return k == 0 ? 0 : +1;
+}
+
+int
+NdbSqlUtil::likeBinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ assert(info == 0);
+ return likeChar(&my_charset_bin, p1, n1, p2, n2);
+}
+
+int
+NdbSqlUtil::likeVarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ const unsigned lb = 1;
+ if (n1 >= lb && n2 >= lb) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = *v1;
+ unsigned m2 = *v2;
+ if (lb + m1 <= n1 && lb + m2 <= n2) {
+ const char* w1 = (const char*)v1 + lb;
+ const char* w2 = (const char*)v2 + lb;
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ int k = (cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
+ return k == 0 ? 0 : +1;
+ }
+ }
+ return -1;
+}
+
+int
+NdbSqlUtil::likeVarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ assert(info == 0);
+ return likeVarchar(&my_charset_bin, p1, n1, p2, n2);
+}
+
+int
+NdbSqlUtil::likeLongvarchar(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ const unsigned lb = 2;
+ if (n1 >= lb && n2 >= lb) {
+ const uchar* v1 = (const uchar*)p1;
+ const uchar* v2 = (const uchar*)p2;
+ unsigned m1 = uint2korr(v1);
+ unsigned m2 = uint2korr(v2);
+ if (lb + m1 <= n1 && lb + m2 <= n2) {
+ const char* w1 = (const char*)v1 + lb;
+ const char* w2 = (const char*)v2 + lb;
+ CHARSET_INFO* cs = (CHARSET_INFO*)(info);
+ int k = (cs->coll->wildcmp)(cs, w1, w1 + m1, w2, w2 + m2, ndb_wild_prefix, ndb_wild_one, ndb_wild_many);
+ return k == 0 ? 0 : +1;
+ }
+ }
+ return -1;
+}
+
+int
+NdbSqlUtil::likeLongvarbinary(const void* info, const void* p1, unsigned n1, const void* p2, unsigned n2)
+{
+ assert(info == 0);
+ return likeLongvarchar(&my_charset_bin, p1, n1, p2, n2);
+}
+
+// check charset
+
+bool
+NdbSqlUtil::usable_in_pk(Uint32 typeId, const void* info)
+{
+ const Type& type = getType(typeId);
+ switch (type.m_typeId) {
+ case Type::Char:
+ case Type::Varchar:
+ case Type::Longvarchar:
+ {
+ const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
+ return
+ cs != 0 &&
+ cs->cset != 0 &&
+ cs->coll != 0 &&
+ cs->coll->strnxfrm != 0 &&
+ cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY;
+ }
+ break;
+ case Type::Undefined:
+ case Type::Blob:
+ case Type::Text:
+ case Type::Bit:
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+bool
+NdbSqlUtil::usable_in_hash_index(Uint32 typeId, const void* info)
+{
+ return usable_in_pk(typeId, info);
+}
+
+bool
+NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info)
+{
+ const Type& type = getType(typeId);
+ if (type.m_cmp == NULL)
+ return false;
+ switch (type.m_typeId) {
+ case Type::Char:
+ case Type::Varchar:
+ case Type::Longvarchar:
+ {
+ const CHARSET_INFO *cs = (const CHARSET_INFO*)info;
+ return
+ cs != 0 &&
+ cs->cset != 0 &&
+ cs->coll != 0 &&
+ cs->coll->strnxfrm != 0 &&
+ cs->coll->strnncollsp != 0 &&
+ cs->strxfrm_multiply <= MAX_XFRM_MULTIPLY;
+ }
+ break;
+ case Type::Undefined:
+ case Type::Blob:
+ case Type::Text:
+ case Type::Bit: // can be fixed
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+// utilities
+
+bool
+NdbSqlUtil::get_var_length(Uint32 typeId, const void* p, unsigned attrlen, Uint32& lb, Uint32& len)
+{
+ const unsigned char* const src = (const unsigned char*)p;
+ switch (typeId) {
+ case NdbSqlUtil::Type::Varchar:
+ case NdbSqlUtil::Type::Varbinary:
+ lb = 1;
+ if (attrlen >= lb) {
+ len = src[0];
+ if (attrlen >= lb + len)
+ return true;
+ }
+ break;
+ case NdbSqlUtil::Type::Longvarchar:
+ case NdbSqlUtil::Type::Longvarbinary:
+ lb = 2;
+ if (attrlen >= lb) {
+ len = src[0] + (src[1] << 8);
+ if (attrlen >= lb + len)
+ return true;
+ }
+ break;
+ default:
+ lb = 0;
+ len = attrlen;
+ return true;
+ break;
+ }
+ return false;
+}
+
+// workaround
+
+int
+NdbSqlUtil::strnxfrm_bug7284(CHARSET_INFO* cs, unsigned char* dst, unsigned dstLen, const unsigned char*src, unsigned srcLen)
+{
+ unsigned char nsp[20]; // native space char
+ unsigned char xsp[20]; // strxfrm-ed space char
+#ifdef VM_TRACE
+ memset(nsp, 0x1f, sizeof(nsp));
+ memset(xsp, 0x1f, sizeof(xsp));
+#endif
+ // convert from unicode codepoint for space
+ int n1 = (*cs->cset->wc_mb)(cs, (my_wc_t)0x20, nsp, nsp + sizeof(nsp));
+ if (n1 <= 0)
+ return -1;
+ // strxfrm to binary
+ int n2 = (*cs->coll->strnxfrm)(cs, xsp, sizeof(xsp), nsp, n1);
+ if (n2 <= 0)
+ return -1;
+ // XXX bug workaround - strnxfrm may not write full string
+ memset(dst, 0x0, dstLen);
+ // strxfrm argument string - returns no error indication
+ int n3 = (*cs->coll->strnxfrm)(cs, dst, dstLen, src, srcLen);
+ // pad with strxfrm-ed space chars
+ int n4 = n3;
+ while (n4 < (int)dstLen) {
+ dst[n4] = xsp[(n4 - n3) % n2];
+ n4++;
+ }
+ // no check for partial last
+ return dstLen;
+}
diff --git a/storage/ndb/src/common/util/OutputStream.cpp b/storage/ndb/src/common/util/OutputStream.cpp
new file mode 100644
index 00000000000..a41eef649dd
--- /dev/null
+++ b/storage/ndb/src/common/util/OutputStream.cpp
@@ -0,0 +1,99 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+
+#include <OutputStream.hpp>
+#include <socket_io.h>
+
+FileOutputStream::FileOutputStream(FILE * file){
+ f = file;
+}
+
+int
+FileOutputStream::print(const char * fmt, ...){
+ va_list ap;
+ va_start(ap, fmt);
+ const int ret = vfprintf(f, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+int
+FileOutputStream::println(const char * fmt, ...){
+ va_list ap;
+ va_start(ap, fmt);
+ const int ret = vfprintf(f, fmt, ap);
+ va_end(ap);
+ return ret + fprintf(f, "\n");
+}
+
+SocketOutputStream::SocketOutputStream(NDB_SOCKET_TYPE socket,
+ unsigned timeout){
+ m_socket = socket;
+ m_timeout = timeout;
+}
+
+int
+SocketOutputStream::print(const char * fmt, ...){
+ va_list ap;
+ va_start(ap, fmt);
+ const int ret = vprint_socket(m_socket, m_timeout, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+int
+SocketOutputStream::println(const char * fmt, ...){
+ va_list ap;
+ va_start(ap, fmt);
+ const int ret = vprintln_socket(m_socket, m_timeout, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+#ifdef NDB_SOFTOSE
+#include <dbgprintf.h>
+int
+SoftOseOutputStream::print(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ else
+ buf[0] = 0;
+ va_end(ap);
+ dbgprintf(buf);
+}
+
+int
+SoftOseOutputStream::println(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ else
+ buf[0] = 0;
+ va_end(ap);
+
+ strcat(buf, "\n\r");
+ dbgprintf(buf);
+}
+#endif
diff --git a/storage/ndb/src/common/util/Parser.cpp b/storage/ndb/src/common/util/Parser.cpp
new file mode 100644
index 00000000000..dea128ccf66
--- /dev/null
+++ b/storage/ndb/src/common/util/Parser.cpp
@@ -0,0 +1,350 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+
+#include "Parser.hpp"
+#include <NdbOut.hpp>
+#include <Properties.hpp>
+#include <Base64.hpp>
+
+#undef DEBUG
+#define DEBUG(x) ndbout << x << endl;
+
+static void trim(char * str);
+
+class ParseInputStream : public InputStream {
+public:
+ ParseInputStream(InputStream & in, bool trim = true, char eofComment = '#');
+
+ char* gets(char * buf, int bufLen);
+ void push_back(const char *);
+private:
+ InputStream & in;
+ char * buffer;
+};
+
+ParseInputStream::ParseInputStream(InputStream & _in,
+ bool /* unused */,
+ char /* unused */)
+ : in(_in){
+ buffer = 0;
+}
+
+char*
+ParseInputStream::gets(char * buf, int bufLen){
+ if(buffer != 0){
+ strncpy(buf, buffer, bufLen);
+ free(buffer);
+ buffer = 0;
+ return buf;
+ }
+ char *t = in.gets(buf, bufLen);
+ return t;
+}
+
+void
+ParseInputStream::push_back(const char * str){
+ if(buffer != 0)
+ abort();
+ buffer = strdup(str);
+}
+
+ParserImpl::ParserImpl(const DummyRow * rows, InputStream & in,
+ bool b_cmd, bool b_empty, bool b_iarg)
+ : m_rows(rows), input(* new ParseInputStream(in))
+{
+ m_breakOnCmd = b_cmd;
+ m_breakOnEmpty = b_empty;
+ m_breakOnInvalidArg = b_iarg;
+}
+
+ParserImpl::~ParserImpl(){
+ delete & input;
+}
+
+static
+bool
+Empty(const char * str){
+ if(str == 0)
+ return true;
+ const int len = strlen(str);
+ if(len == 0)
+ return false;
+ for(int i = 0; i<len; i++)
+ if(str[i] != ' ' && str[i] != '\t' && str[i] != '\n')
+ return false;
+ return true;
+}
+
+static
+bool
+Eof(const char * str) { return str == 0;}
+
+static
+void
+trim(char * str){
+ if(str == NULL)
+ return;
+ int len = strlen(str);
+ for(len--; str[len] == '\n' || str[len] == ' ' || str[len] == '\t'; len--)
+ str[len] = 0;
+
+ int pos = 0;
+ while(str[pos] == ' ' || str[pos] == '\t')
+ pos++;
+
+ if(str[pos] == '\"' && str[len] == '\"') {
+ pos++;
+ str[len] = 0;
+ len--;
+ }
+
+ memmove(str, &str[pos], len - pos + 2);
+}
+
+static
+bool
+split(char * buf, char ** name, char ** value){
+
+ * value = strchr(buf, ':');
+ if(* value == 0)
+ * value = strchr(buf, '=');
+
+
+ if(* value == 0){
+ return false;
+ }
+ (* value)[0] = 0;
+ * value = (* value + 1);
+ * name = buf;
+
+ trim(* name);
+ trim(* value);
+
+ return true;
+}
+
+bool
+ParserImpl::run(Context * ctx, const class Properties ** pDst,
+ volatile bool * stop) const {
+ * pDst = 0;
+ bool ownStop = false;
+ if(stop == 0)
+ stop = &ownStop;
+
+ ctx->m_aliasUsed.clear();
+
+ const unsigned sz = sizeof(ctx->m_tokenBuffer);
+ ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
+ if(Eof(ctx->m_currentToken)){
+ ctx->m_status = Parser<Dummy>::Eof;
+ return false;
+ }
+
+ if(ctx->m_currentToken[0] == 0){
+ ctx->m_status = Parser<Dummy>::NoLine;
+ return false;
+ }
+
+ if(Empty(ctx->m_currentToken)){
+ ctx->m_status = Parser<Dummy>::EmptyLine;
+ return false;
+ }
+
+ trim(ctx->m_currentToken);
+ ctx->m_currentCmd = matchCommand(ctx, ctx->m_currentToken, m_rows);
+ if(ctx->m_currentCmd == 0){
+ ctx->m_status = Parser<Dummy>::UnknownCommand;
+ return false;
+ }
+
+ Properties * p = new Properties();
+
+ bool invalidArgument = false;
+ ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
+
+ while((! * stop) &&
+ !Eof(ctx->m_currentToken) &&
+ !Empty(ctx->m_currentToken)){
+ if(ctx->m_currentToken[0] != 0){
+ trim(ctx->m_currentToken);
+ if(!parseArg(ctx, ctx->m_currentToken, ctx->m_currentCmd + 1, p)){
+ delete p;
+ invalidArgument = true;
+ break;
+ }
+ }
+ ctx->m_currentToken = input.gets(ctx->m_tokenBuffer, sz);
+ }
+
+ if(invalidArgument){
+ char buf[sz];
+ char * tmp;
+ if(!m_breakOnInvalidArg){
+ do {
+ tmp = input.gets(buf, sz);
+ } while((! * stop) && !Eof(tmp) && !Empty(tmp));
+ }
+ return false;
+ }
+
+ if(* stop){
+ delete p;
+ ctx->m_status = Parser<Dummy>::ExternalStop;
+ return false;
+ }
+
+ if(!checkMandatory(ctx, p)){
+ ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
+ delete p;
+ return false;
+ }
+
+ /**
+ * Add alias to properties
+ */
+ for(unsigned i = 0; i<ctx->m_aliasUsed.size(); i++){
+ const ParserRow<Dummy> * alias = ctx->m_aliasUsed[i];
+ Properties tmp;
+ tmp.put("name", alias->name);
+ tmp.put("realName", alias->realName);
+ p->put("$ALIAS", i, &tmp);
+ }
+ p->put("$ALIAS", ctx->m_aliasUsed.size());
+
+ ctx->m_status = Parser<Dummy>::Ok;
+ * pDst = p;
+ return true;
+}
+
+const ParserImpl::DummyRow*
+ParserImpl::matchCommand(Context* ctx, const char* buf, const DummyRow rows[]){
+ const char * name = buf;
+ const DummyRow * tmp = &rows[0];
+ while(tmp->name != 0 && name != 0){
+ if(strcmp(tmp->name, name) == 0){
+ if(tmp->type == DummyRow::Cmd)
+ return tmp;
+ if(tmp->type == DummyRow::CmdAlias){
+ if(ctx != 0)
+ ctx->m_aliasUsed.push_back(tmp);
+ name = tmp->realName;
+ tmp = &rows[0];
+ continue;
+ }
+ }
+ tmp++;
+ }
+ return 0;
+}
+
+const ParserImpl::DummyRow*
+ParserImpl::matchArg(Context* ctx, const char * buf, const DummyRow rows[]){
+ const char * name = buf;
+ const DummyRow * tmp = &rows[0];
+ while(tmp->name != 0){
+ const DummyRow::Type t = tmp->type;
+ if(t != DummyRow::Arg && t != DummyRow::ArgAlias && t !=DummyRow::CmdAlias)
+ break;
+ if(t !=DummyRow::CmdAlias && strcmp(tmp->name, name) == 0){
+ if(tmp->type == DummyRow::Arg){
+ return tmp;
+ }
+ if(tmp->type == DummyRow::ArgAlias){
+ if(ctx != 0)
+ ctx->m_aliasUsed.push_back(tmp);
+ name = tmp->realName;
+ tmp = &rows[0];
+ continue;
+ }
+ }
+ tmp++;
+ }
+ return 0;
+}
+
+bool
+ParserImpl::parseArg(Context * ctx,
+ char * buf,
+ const DummyRow * rows,
+ Properties * p){
+ char * name;
+ char * value;
+ if(!split(buf, &name, &value)){
+ ctx->m_status = Parser<Dummy>::InvalidArgumentFormat;
+ return false;
+ }
+ const DummyRow * arg = matchArg(ctx, name, rows);
+ if(arg == 0){
+ ctx->m_status = Parser<Dummy>::UnknownArgument;
+ return false;
+ }
+
+ switch(arg->argType){
+ case DummyRow::String:
+ if(p->put(arg->name, value))
+ return true;
+ break;
+ case DummyRow::Int:{
+ Uint32 i;
+ int c = sscanf(value, "%u", &i);
+ if(c != 1){
+ ctx->m_status = Parser<Dummy>::TypeMismatch;
+ return false;
+ }
+ if(p->put(arg->name, i))
+ return true;
+ break;
+ }
+
+ case DummyRow::Properties: {
+ Properties *sp = new Properties();
+ BaseString v(value);
+ UtilBuffer b;
+ base64_decode(v, b);
+ sp->unpack((const Uint32 *)b.get_data(), b.length());
+ break;
+ }
+ default:
+ ctx->m_status = Parser<Dummy>::UnknownArgumentType;
+ return false;
+ }
+ if(p->getPropertiesErrno() == E_PROPERTIES_ELEMENT_ALREADY_EXISTS){
+ ctx->m_status = Parser<Dummy>::ArgumentGivenTwice;
+ return false;
+ }
+
+ abort();
+}
+
+bool
+ParserImpl::checkMandatory(Context* ctx, const Properties* props){
+ const DummyRow * tmp = &ctx->m_currentCmd[1];
+ while(tmp->name != 0 && tmp->type == DummyRow::Arg){
+ if(tmp->argRequired == ParserRow<Dummy>::Mandatory &&
+ !props->contains(tmp->name)){
+ ctx->m_status = Parser<Dummy>::MissingMandatoryArgument;
+ ctx->m_currentArg = tmp;
+ return false;
+ }
+ tmp++;
+ }
+ return true;
+}
+
+template class Vector<const ParserRow<ParserImpl::Dummy>*>;
diff --git a/storage/ndb/src/common/util/Properties.cpp b/storage/ndb/src/common/util/Properties.cpp
new file mode 100644
index 00000000000..0edcda0e726
--- /dev/null
+++ b/storage/ndb/src/common/util/Properties.cpp
@@ -0,0 +1,1136 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+
+#include <Properties.hpp>
+
+#include <NdbTCP.h>
+#include <NdbOut.hpp>
+
+static
+char * f_strdup(const char * s){
+ if(!s) return 0;
+ return strdup(s);
+}
+
+/**
+ * Note has to be a multiple of 4 bytes
+ */
+const char Properties::version[] = { 2, 0, 0, 1, 1, 1, 1, 4 };
+const char Properties::delimiter = ':';
+
+/**
+ * PropertyImpl
+ */
+struct PropertyImpl{
+ PropertiesType valueType;
+ const char * name;
+ void * value;
+
+ ~PropertyImpl();
+ PropertyImpl(const char * name, Uint32 value);
+ PropertyImpl(const char * name, Uint64 value);
+ PropertyImpl(const char * name, const char * value);
+ PropertyImpl(const char * name, const Properties * value);
+
+ static PropertyImpl * copyPropertyImpl(const PropertyImpl &);
+};
+
+/**
+ * PropertiesImpl
+ */
+class PropertiesImpl {
+ PropertiesImpl(const PropertiesImpl &); // Not implemented
+ PropertiesImpl& operator=(const PropertiesImpl&); // Not implemented
+public:
+ PropertiesImpl(Properties *, bool case_insensitive);
+ PropertiesImpl(Properties *, const PropertiesImpl &);
+ ~PropertiesImpl();
+
+ Properties * properties;
+
+ Uint32 size;
+ Uint32 items;
+ PropertyImpl **content;
+
+ bool m_insensitive;
+ int (* compare)(const char *s1, const char *s2);
+
+ void setCaseInsensitiveNames(bool value);
+ void grow(int sizeToAdd);
+
+ PropertyImpl * get(const char * name) const;
+ PropertyImpl * put(PropertyImpl *);
+ void remove(const char * name);
+
+ Uint32 getPackedSize(Uint32 pLen) const;
+ bool pack(Uint32 *& buf, const char * prefix, Uint32 prefixLen) const;
+ bool unpack(const Uint32 * buf, Uint32 &bufLen, Properties * top, int items);
+
+ Uint32 getTotalItems() const;
+
+ void setErrno(Uint32 pErr, Uint32 osErr = 0){
+ properties->setErrno(pErr, osErr);
+ }
+
+ const char * getProps(const char * name, const PropertiesImpl ** impl) const;
+ const char * getPropsPut(const char * name, PropertiesImpl ** impl);
+};
+
+/**
+ * Methods for Property
+ */
+Property::Property(const char * name, Uint32 value){
+ impl = new PropertyImpl(name, value);
+}
+
+Property::Property(const char * name, const char * value){
+ impl = new PropertyImpl(name, value);
+}
+
+Property::Property(const char * name, const class Properties * value){
+ impl = new PropertyImpl(name, value);
+
+ ((Properties*)impl->value)->setCaseInsensitiveNames(value->getCaseInsensitiveNames());
+}
+
+Property::~Property(){
+ delete impl;
+}
+
+/**
+ * Methods for Properties
+ */
+Properties::Properties(bool case_insensitive){
+ parent = 0;
+ impl = new PropertiesImpl(this, case_insensitive);
+}
+
+Properties::Properties(const Properties & org){
+ parent = 0;
+ impl = new PropertiesImpl(this, * org.impl);
+}
+
+Properties::Properties(const Property * anArray, int arrayLen){
+ impl = new PropertiesImpl(this, false);
+
+ put(anArray, arrayLen);
+}
+
+Properties::~Properties(){
+ clear();
+ delete impl;
+}
+
+void
+Properties::put(const Property * anArray, int arrayLen){
+ if(anArray == 0)
+ return;
+ for(int i = 0; i<arrayLen; i++)
+ impl->put(anArray[i].impl);
+}
+
+template <class T>
+bool
+put(PropertiesImpl * impl, const char * name, T value, bool replace){
+ if(name == 0){
+ impl->setErrno(E_PROPERTIES_INVALID_NAME);
+ return false;
+ }
+
+ PropertiesImpl * tmp = 0;
+ const char * short_name = impl->getPropsPut(name, &tmp);
+
+ if(tmp == 0){
+ impl->setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+
+ if(tmp->get(short_name) != 0){
+ if(replace){
+ tmp->remove(short_name);
+ } else {
+ impl->setErrno(E_PROPERTIES_ELEMENT_ALREADY_EXISTS);
+ return false;
+ }
+ }
+ return tmp->put(new PropertyImpl(short_name, value));
+}
+
+
+bool
+Properties::put(const char * name, Uint32 value, bool replace){
+ return ::put(impl, name, value, replace);
+}
+
+bool
+Properties::put64(const char * name, Uint64 value, bool replace){
+ return ::put(impl, name, value, replace);
+}
+
+bool
+Properties::put(const char * name, const char * value, bool replace){
+ return ::put(impl, name, value, replace);
+}
+
+bool
+Properties::put(const char * name, const Properties * value, bool replace){
+ return ::put(impl, name, value, replace);
+}
+
+bool
+Properties::getTypeOf(const char * name, PropertiesType * type) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+ setErrno(E_PROPERTIES_OK);
+ * type = nvp->valueType;
+ return true;
+}
+
+bool
+Properties::contains(const char * name) const {
+ PropertyImpl * nvp = impl->get(name);
+ return nvp != 0;
+}
+
+bool
+Properties::get(const char * name, Uint32 * value) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+
+ if(nvp->valueType == PropertiesType_Uint32){
+ * value = * (Uint32 *)nvp->value;
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+
+ if(nvp->valueType == PropertiesType_Uint64){
+ Uint64 tmp = * (Uint64 *)nvp->value;
+ Uint64 max = 1; max <<= 32;
+ if(tmp < max){
+ * value = (Uint32)tmp;
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+ }
+ setErrno(E_PROPERTIES_INVALID_TYPE);
+ return false;
+}
+
+bool
+Properties::get(const char * name, Uint64 * value) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+
+ if(nvp->valueType == PropertiesType_Uint32){
+ Uint32 tmp = * (Uint32 *)nvp->value;
+ * value = (Uint64)tmp;
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+
+ if(nvp->valueType == PropertiesType_Uint64){
+ * value = * (Uint64 *)nvp->value;
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+ setErrno(E_PROPERTIES_INVALID_TYPE);
+ return false;
+}
+
+bool
+Properties::get(const char * name, const char ** value) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+
+ if(nvp->valueType == PropertiesType_char){
+ * value = (const char *)nvp->value;
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+ setErrno(E_PROPERTIES_INVALID_TYPE);
+ return false;
+}
+
+bool
+Properties::get(const char * name, BaseString& value) const {
+ const char *tmp = "";
+ bool ret;
+ ret = get(name, &tmp);
+ value.assign(tmp);
+ return ret;
+}
+
+bool
+Properties::get(const char * name, const Properties ** value) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+ if(nvp->valueType == PropertiesType_Properties){
+ * value = (const Properties *)nvp->value;
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+ setErrno(E_PROPERTIES_INVALID_TYPE);
+ return false;
+}
+
+bool
+Properties::getCopy(const char * name, char ** value) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+
+ if(nvp->valueType == PropertiesType_char){
+ * value = f_strdup((const char *)nvp->value);
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+ setErrno(E_PROPERTIES_INVALID_TYPE);
+ return false;
+}
+
+bool
+Properties::getCopy(const char * name, Properties ** value) const {
+ PropertyImpl * nvp = impl->get(name);
+ if(nvp == 0){
+ setErrno(E_PROPERTIES_NO_SUCH_ELEMENT);
+ return false;
+ }
+
+ if(nvp->valueType == PropertiesType_Properties){
+ * value = new Properties(* (const Properties *)nvp->value);
+ setErrno(E_PROPERTIES_OK);
+ return true;
+ }
+ setErrno(E_PROPERTIES_INVALID_TYPE);
+ return false;
+}
+
+void
+Properties::clear(){
+ while(impl->items > 0)
+ impl->remove(impl->content[0]->name);
+}
+
+void
+Properties::remove(const char * name) {
+ impl->remove(name);
+}
+
+void
+Properties::print(FILE * out, const char * prefix) const{
+ char buf[1024];
+ if(prefix == 0)
+ buf[0] = 0;
+ else
+ strncpy(buf, prefix, 1024);
+
+ for(unsigned int i = 0; i<impl->items; i++){
+ switch(impl->content[i]->valueType){
+ case PropertiesType_Uint32:
+ fprintf(out, "%s%s = (Uint32) %d\n", buf, impl->content[i]->name,
+ *(Uint32 *)impl->content[i]->value);
+ break;
+ case PropertiesType_Uint64:
+ fprintf(out, "%s%s = (Uint64) %lld\n", buf, impl->content[i]->name,
+ *(Uint64 *)impl->content[i]->value);
+ break;
+ case PropertiesType_char:
+ fprintf(out, "%s%s = (char*) \"%s\"\n", buf, impl->content[i]->name,
+ (char *)impl->content[i]->value);
+ break;
+ case PropertiesType_Properties:
+ char buf2 [1024];
+ BaseString::snprintf(buf2, sizeof(buf2), "%s%s%c",buf, impl->content[i]->name,
+ Properties::delimiter);
+ ((Properties *)impl->content[i]->value)->print(out, buf2);
+ break;
+ }
+ }
+}
+
+Properties::Iterator::Iterator(const Properties* prop) :
+ m_prop(prop),
+ m_iterator(0) {
+}
+
+const char*
+Properties::Iterator::first() {
+ m_iterator = 0;
+ return next();
+}
+
+const char*
+Properties::Iterator::next() {
+ if (m_iterator < m_prop->impl->items)
+ return m_prop->impl->content[m_iterator++]->name;
+ else
+ return NULL;
+}
+
+Uint32
+Properties::getPackedSize() const {
+ Uint32 sz = 0;
+
+ sz += sizeof(version); // Version id of properties object
+ sz += 4; // No Of Items
+ sz += 4; // Checksum
+
+ return sz + impl->getPackedSize(0);
+}
+
+static
+Uint32
+computeChecksum(const Uint32 * buf, Uint32 words){
+ Uint32 sum = 0;
+ for(unsigned int i = 0; i<words; i++)
+ sum ^= htonl(buf[i]);
+
+ return sum;
+}
+
+bool
+Properties::pack(Uint32 * buf) const {
+ Uint32 * bufStart = buf;
+
+ memcpy(buf, version, sizeof(version));
+
+ // Note that version must be a multiple of 4
+ buf += (sizeof(version) / 4);
+
+ * buf = htonl(impl->getTotalItems());
+ buf++;
+ bool res = impl->pack(buf, "", 0);
+ if(!res)
+ return res;
+
+ * buf = htonl(computeChecksum(bufStart, (buf - bufStart)));
+
+ return true;
+}
+
+bool
+Properties::unpack(const Uint32 * buf, Uint32 bufLen){
+ const Uint32 * bufStart = buf;
+ Uint32 bufLenOrg = bufLen;
+
+ if(bufLen < sizeof(version)){
+ setErrno(E_PROPERTIES_INVALID_BUFFER_TO_SHORT);
+ return false;
+ }
+
+ if(memcmp(buf, version, sizeof(version)) != 0){
+ setErrno(E_PROPERTIES_INVALID_VERSION_WHILE_UNPACKING);
+ return false;
+ }
+ bufLen -= sizeof(version);
+
+ // Note that version must be a multiple of 4
+ buf += (sizeof(version) / 4);
+
+ if(bufLen < 4){
+ setErrno(E_PROPERTIES_INVALID_BUFFER_TO_SHORT);
+ return false;
+ }
+
+ Uint32 totalItems = ntohl(* buf);
+ buf++; bufLen -= 4;
+ bool res = impl->unpack(buf, bufLen, this, totalItems);
+ if(!res)
+ return res;
+
+ Uint32 sum = computeChecksum(bufStart, (bufLenOrg-bufLen)/4);
+ if(sum != ntohl(bufStart[(bufLenOrg-bufLen)/4])){
+ setErrno(E_PROPERTIES_INVALID_CHECKSUM);
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Methods for PropertiesImpl
+ */
+PropertiesImpl::PropertiesImpl(Properties * p, bool case_insensitive){
+ this->properties = p;
+ items = 0;
+ size = 25;
+ content = new PropertyImpl * [size];
+ setCaseInsensitiveNames(case_insensitive);
+}
+
+PropertiesImpl::PropertiesImpl(Properties * p, const PropertiesImpl & org){
+ this->properties = p;
+ this->size = org.size;
+ this->items = org.items;
+ this->m_insensitive = org.m_insensitive;
+ this->compare = org.compare;
+ content = new PropertyImpl * [size];
+ for(unsigned int i = 0; i<items; i++){
+ content[i] = PropertyImpl::copyPropertyImpl(* org.content[i]);
+ }
+}
+
+PropertiesImpl::~PropertiesImpl(){
+ for(unsigned int i = 0; i<items; i++)
+ delete content[i];
+ delete [] content;
+}
+
+void
+PropertiesImpl::setCaseInsensitiveNames(bool value){
+ m_insensitive = value;
+ if(value)
+ compare = strcasecmp;
+ else
+ compare = strcmp;
+}
+
+void
+PropertiesImpl::grow(int sizeToAdd){
+ PropertyImpl ** newContent = new PropertyImpl * [size + sizeToAdd];
+ memcpy(newContent, content, items * sizeof(PropertyImpl *));
+ delete [] content;
+ content = newContent;
+ size += sizeToAdd;
+}
+
+PropertyImpl *
+PropertiesImpl::get(const char * name) const {
+ const PropertiesImpl * tmp = 0;
+ const char * short_name = getProps(name, &tmp);
+ if(tmp == 0){
+ return 0;
+ }
+
+ for(unsigned int i = 0; i<tmp->items; i++) {
+ if((* compare)(tmp->content[i]->name, short_name) == 0)
+ return tmp->content[i];
+ }
+
+ return 0;
+}
+
+PropertyImpl *
+PropertiesImpl::put(PropertyImpl * nvp){
+ if(items == size)
+ grow(size);
+ content[items] = nvp;
+
+ items ++;
+
+ if(nvp->valueType == PropertiesType_Properties){
+ ((Properties*)nvp->value)->parent = properties;
+ }
+ return nvp;
+}
+
+void
+PropertiesImpl::remove(const char * name){
+ for(unsigned int i = 0; i<items; i++){
+ if((* compare)(content[i]->name, name) == 0){
+ delete content[i];
+ memmove(&content[i], &content[i+1], (items-i-1)*sizeof(PropertyImpl *));
+ items --;
+ return;
+ }
+ }
+}
+
+Uint32
+PropertiesImpl::getTotalItems() const {
+ int ret = 0;
+ for(unsigned int i = 0; i<items; i++)
+ if(content[i]->valueType == PropertiesType_Properties){
+ ret += ((Properties*)content[i]->value)->impl->getTotalItems();
+ } else {
+ ret ++;
+ }
+ return ret;
+}
+
+const char *
+PropertiesImpl::getProps(const char * name,
+ const PropertiesImpl ** impl) const {
+ const char * ret = name;
+ const char * tmp = strchr(name, Properties::delimiter);
+ if(tmp == 0){
+ * impl = this;
+ return ret;
+ } else {
+ Uint32 sz = tmp - name;
+ char * tmp2 = (char*)malloc(sz + 1);
+ memcpy(tmp2, name, sz);
+ tmp2[sz] = 0;
+
+ PropertyImpl * nvp = get(tmp2);
+
+ free(tmp2);
+
+ if(nvp == 0){
+ * impl = 0;
+ return 0;
+ }
+ if(nvp->valueType != PropertiesType_Properties){
+ * impl = 0;
+ return name;
+ }
+ return ((Properties*)nvp->value)->impl->getProps(tmp+1, impl);
+ }
+}
+
+const char *
+PropertiesImpl::getPropsPut(const char * name,
+ PropertiesImpl ** impl) {
+ const char * ret = name;
+ const char * tmp = strchr(name, Properties::delimiter);
+ if(tmp == 0){
+ * impl = this;
+ return ret;
+ } else {
+ Uint32 sz = tmp - name;
+ char * tmp2 = (char*)malloc(sz + 1);
+ memcpy(tmp2, name, sz);
+ tmp2[sz] = 0;
+
+ PropertyImpl * nvp = get(tmp2);
+
+ if(nvp == 0){
+ Properties * tmpP = new Properties();
+ PropertyImpl * tmpPI = new PropertyImpl(tmp2, tmpP);
+ PropertyImpl * nvp = put(tmpPI);
+
+ delete tmpP;
+ free(tmp2);
+ return ((Properties*)nvp->value)->impl->getPropsPut(tmp+1, impl);
+ }
+ free(tmp2);
+ if(nvp->valueType != PropertiesType_Properties){
+ * impl = 0;
+ return name;
+ }
+ return ((Properties*)nvp->value)->impl->getPropsPut(tmp+1, impl);
+ }
+}
+
+int
+mod4(unsigned int i){
+ int res = i + (4 - (i % 4));
+ return res;
+}
+
+Uint32
+PropertiesImpl::getPackedSize(Uint32 pLen) const {
+ Uint32 sz = 0;
+ for(unsigned int i = 0; i<items; i++){
+ if(content[i]->valueType == PropertiesType_Properties){
+ Properties * p = (Properties*)content[i]->value;
+ sz += p->impl->getPackedSize(pLen+strlen(content[i]->name)+1);
+ } else {
+ sz += 4; // Type
+ sz += 4; // Name Len
+ sz += 4; // Value Len
+ sz += mod4(pLen + strlen(content[i]->name)); // Name
+ switch(content[i]->valueType){
+ case PropertiesType_char:
+ sz += mod4(strlen((char *)content[i]->value));
+ break;
+ case PropertiesType_Uint32:
+ sz += mod4(4);
+ break;
+ case PropertiesType_Uint64:
+ sz += mod4(8);
+ break;
+ case PropertiesType_Properties:
+ default:
+ assert(0);
+ }
+ }
+ }
+ return sz;
+}
+
+struct CharBuf {
+ char * buffer;
+ Uint32 bufLen;
+ Uint32 contentLen;
+
+ CharBuf(){
+ buffer = 0;
+ bufLen = 0;
+ contentLen = 0;
+ }
+
+ ~CharBuf(){
+ free(buffer);
+ }
+
+ void clear() { contentLen = 0;}
+ bool add(const char * str, Uint32 strLen){
+ if(!expand(contentLen + strLen + 1))
+ return false;
+ memcpy(&buffer[contentLen], str, strLen);
+ contentLen += strLen;
+ buffer[contentLen] = 0;
+ return true;
+ }
+
+ bool add(char c){
+ return add(&c, 1);
+ }
+
+ bool expand(Uint32 newSize){
+ if(newSize >= bufLen){
+
+ char * tmp = (char*)malloc(newSize + 1024);
+ memset(tmp, 0, newSize + 1024);
+ if(tmp == 0)
+ return false;
+ if(contentLen > 0)
+ memcpy(tmp, buffer, contentLen);
+ if(buffer != 0)
+ free(buffer);
+ buffer = tmp;
+ bufLen = newSize + 1024;
+ }
+ return true;
+ }
+};
+
+bool
+PropertiesImpl::pack(Uint32 *& buf, const char * prefix, Uint32 pLen) const {
+ CharBuf charBuf;
+
+ for(unsigned int i = 0; i<items; i++){
+ const int strLenName = strlen(content[i]->name);
+
+ if(content[i]->valueType == PropertiesType_Properties){
+ charBuf.clear();
+ if(!charBuf.add(prefix, pLen)){
+ properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING,
+ errno);
+ return false;
+ }
+
+ if(!charBuf.add(content[i]->name, strLenName)){
+ properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING,
+ errno);
+ return false;
+ }
+
+ if(!charBuf.add(Properties::delimiter)){
+ properties->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING,
+ errno);
+ return false;
+ }
+
+ if(!((Properties*)(content[i]->value))->impl->pack(buf,
+ charBuf.buffer,
+ charBuf.contentLen)){
+
+ return false;
+ }
+ continue;
+ }
+
+ Uint32 valLenData = 0;
+ Uint32 valLenWrite = 0;
+ Uint32 sz = 4 + 4 + 4 + mod4(pLen + strLenName);
+ switch(content[i]->valueType){
+ case PropertiesType_Uint32:
+ valLenData = 4;
+ break;
+ case PropertiesType_Uint64:
+ valLenData = 8;
+ break;
+ case PropertiesType_char:
+ valLenData = strlen((char *)content[i]->value);
+ break;
+ case PropertiesType_Properties:
+ assert(0);
+ }
+ valLenWrite = mod4(valLenData);
+ sz += valLenWrite;
+
+ * (buf + 0) = htonl(content[i]->valueType);
+ * (buf + 1) = htonl(pLen + strLenName);
+ * (buf + 2) = htonl(valLenData);
+
+ char * valBuf = (char*)(buf + 3);
+ char * nameBuf = (char*)(buf + 3 + (valLenWrite / 4));
+
+ memset(valBuf, 0, sz-12);
+
+ switch(content[i]->valueType){
+ case PropertiesType_Uint32:
+ * (Uint32 *)valBuf = htonl(* (Uint32 *)content[i]->value);
+ break;
+ case PropertiesType_Uint64:{
+ Uint64 val = * (Uint64 *)content[i]->value;
+ Uint32 hi = (val >> 32);
+ Uint32 lo = (val & 0xFFFFFFFF);
+ * (Uint32 *)valBuf = htonl(hi);
+ * (Uint32 *)(valBuf + 4) = htonl(lo);
+ }
+ break;
+ case PropertiesType_char:
+ memcpy(valBuf, content[i]->value, strlen((char*)content[i]->value));
+ break;
+ case PropertiesType_Properties:
+ assert(0);
+ }
+ if(pLen > 0)
+ memcpy(nameBuf, prefix, pLen);
+ memcpy(nameBuf + pLen, content[i]->name, strLenName);
+
+ buf += (sz / 4);
+ }
+
+ return true;
+}
+
+bool
+PropertiesImpl::unpack(const Uint32 * buf, Uint32 &bufLen, Properties * top,
+ int _items){
+ CharBuf charBuf;
+ while(_items > 0){
+ Uint32 tmp[3];
+
+ if(bufLen <= 12){
+ top->setErrno(E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING);
+ return false;
+ }
+
+ tmp[0] = ntohl(buf[0]);
+ tmp[1] = ntohl(buf[1]);
+ tmp[2] = ntohl(buf[2]);
+ buf += 3;
+ bufLen -= 12;
+
+ PropertiesType pt = (PropertiesType)tmp[0];
+ Uint32 nameLen = tmp[1];
+ Uint32 valueLen = tmp[2];
+ Uint32 nameLenRead = mod4(nameLen);
+ Uint32 valueLenRead = mod4(valueLen);
+
+ Uint32 sz = nameLenRead + valueLenRead;
+ if(bufLen < sz){
+ top->setErrno(E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING);
+ return false;
+ }
+
+ if(!charBuf.expand(sz)){
+ top->setErrno(E_PROPERTIES_ERROR_MALLOC_WHILE_UNPACKING, errno);
+ return false;
+ }
+
+ memcpy(charBuf.buffer, buf, sz);
+ buf += (sz / 4);
+ bufLen -= sz ;
+
+ char * valBuf = charBuf.buffer;
+ char * nameBuf = charBuf.buffer + valueLenRead;
+
+ nameBuf[nameLen] = 0;
+ valBuf[valueLen] = 0;
+
+ bool res3 = false;
+ switch(pt){
+ case PropertiesType_Uint32:
+ res3 = top->put(nameBuf, ntohl(* (Uint32 *)valBuf), true);
+ break;
+ case PropertiesType_Uint64:{
+ Uint64 hi = ntohl(* (Uint32 *)valBuf);
+ Uint64 lo = ntohl(* (Uint32 *)(valBuf + 4));
+ res3 = top->put64(nameBuf, (hi << 32) + lo, true);
+ }
+ break;
+ case PropertiesType_char:
+ res3 = top->put(nameBuf, valBuf, true);
+ break;
+ case PropertiesType_Properties:
+ assert(0);
+ }
+ if(!res3){
+ return false;
+ }
+ _items--;
+ }
+ return true;
+}
+
+PropertyImpl::~PropertyImpl(){
+ free((char*)name);
+ switch(valueType){
+ case PropertiesType_Uint32:
+ delete (Uint32 *)value;
+ break;
+ case PropertiesType_Uint64:
+ delete (Uint64 *)value;
+ break;
+ case PropertiesType_char:
+ free((char *)value);
+ break;
+ case PropertiesType_Properties:
+ delete (Properties *)value;
+ break;
+ }
+}
+
+PropertyImpl *
+PropertyImpl::copyPropertyImpl(const PropertyImpl & org){
+ switch(org.valueType){
+ case PropertiesType_Uint32:
+ return new PropertyImpl(org.name, * (Uint32 *)org.value);
+ case PropertiesType_Uint64:
+ return new PropertyImpl(org.name, * (Uint64 *)org.value);
+ break;
+ case PropertiesType_char:
+ return new PropertyImpl(org.name, (char *)org.value);
+ break;
+ case PropertiesType_Properties:
+ return new PropertyImpl(org.name, (Properties *)org.value);
+ break;
+ default:
+ assert(0);
+ }
+ return 0;
+}
+
+PropertyImpl::PropertyImpl(const char * _name, Uint32 _value){
+ this->name = f_strdup(_name);
+ this->value = new Uint32;
+ * ((Uint32 *)this->value) = _value;
+ this->valueType = PropertiesType_Uint32;
+}
+
+PropertyImpl::PropertyImpl(const char * _name, Uint64 _value){
+ this->name = f_strdup(_name);
+ this->value = new Uint64;
+ * ((Uint64 *)this->value) = _value;
+ this->valueType = PropertiesType_Uint64;
+}
+
+PropertyImpl::PropertyImpl(const char * _name, const char * _value){
+ this->name = f_strdup(_name);
+ this->value = f_strdup(_value);
+ this->valueType = PropertiesType_char;
+
+}
+
+PropertyImpl::PropertyImpl(const char * _name, const Properties * _value){
+ this->name = f_strdup(_name);
+ this->value = new Properties(* _value);
+ this->valueType = PropertiesType_Properties;
+}
+
+const Uint32 E_PROPERTIES_OK = 0;
+const Uint32 E_PROPERTIES_INVALID_NAME = 1;
+const Uint32 E_PROPERTIES_NO_SUCH_ELEMENT = 2;
+const Uint32 E_PROPERTIES_INVALID_TYPE = 3;
+const Uint32 E_PROPERTIES_ELEMENT_ALREADY_EXISTS = 4;
+
+const Uint32 E_PROPERTIES_ERROR_MALLOC_WHILE_PACKING = 5;
+const Uint32 E_PROPERTIES_INVALID_VERSION_WHILE_UNPACKING = 6;
+const Uint32 E_PROPERTIES_INVALID_BUFFER_TO_SHORT = 7;
+const Uint32 E_PROPERTIES_ERROR_MALLOC_WHILE_UNPACKING = 8;
+const Uint32 E_PROPERTIES_INVALID_CHECKSUM = 9;
+const Uint32 E_PROPERTIES_BUFFER_TO_SMALL_WHILE_UNPACKING = 10;
+
+/**
+ * These are methods that used to be inline
+ *
+ * But Diab 4.1f could not compile -release with to many inlines
+ */
+void
+Properties::setErrno(Uint32 pErr, Uint32 osErr) const {
+ if(parent != 0){
+ parent->setErrno(pErr, osErr);
+ return ;
+ }
+
+ /**
+ * propErrno & osErrno used to be mutable,
+ * but diab didn't know what mutable meant.
+ */
+ *((Uint32*)&propErrno) = pErr;
+ *((Uint32*)&osErrno) = osErr;
+}
+
+/**
+ * Inlined get/put(name, no, ...) - methods
+ */
+
+bool
+Properties::put(const char * name, Uint32 no, Uint32 val, bool replace){
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = put(tmp, val, replace);
+ free(tmp);
+ return res;
+}
+
+bool
+Properties::put64(const char * name, Uint32 no, Uint64 val, bool replace){
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = put(tmp, val, replace);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::put(const char * name, Uint32 no, const char * val, bool replace){
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = put(tmp, val, replace);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::put(const char * name, Uint32 no, const Properties * val,
+ bool replace){
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = put(tmp, val, replace);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::getTypeOf(const char * name, Uint32 no,
+ PropertiesType * type) const {
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = getTypeOf(tmp, type);
+ free(tmp);
+ return res;
+}
+
+bool
+Properties::contains(const char * name, Uint32 no) const {
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = contains(tmp);
+ free(tmp);
+ return res;
+}
+
+bool
+Properties::get(const char * name, Uint32 no, Uint32 * value) const{
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = get(tmp, value);
+ free(tmp);
+ return res;
+}
+
+bool
+Properties::get(const char * name, Uint32 no, Uint64 * value) const{
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = get(tmp, value);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::get(const char * name, Uint32 no, const char ** value) const {
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = get(tmp, value);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::get(const char * name, Uint32 no, const Properties ** value) const{
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = get(tmp, value);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::getCopy(const char * name, Uint32 no, char ** value) const {
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = getCopy(tmp, value);
+ free(tmp);
+ return res;
+}
+
+
+bool
+Properties::getCopy(const char * name, Uint32 no, Properties ** value) const {
+ size_t tmp_len = strlen(name)+20;
+ char * tmp = (char*)malloc(tmp_len);
+ BaseString::snprintf(tmp, tmp_len, "%s_%d", name, no);
+ bool res = getCopy(tmp, value);
+ free(tmp);
+ return res;
+}
+
+void
+Properties::setCaseInsensitiveNames(bool value){
+ impl->setCaseInsensitiveNames(value);
+}
+
+bool
+Properties::getCaseInsensitiveNames() const {
+ return impl->m_insensitive;
+}
+
+template bool put(PropertiesImpl *, const char *, Uint32, bool);
+template bool put(PropertiesImpl *, const char *, Uint64, bool);
+template bool put(PropertiesImpl *, const char *, const char *, bool);
+template bool put(PropertiesImpl *, const char *, const Properties*, bool);
diff --git a/storage/ndb/src/common/util/SimpleProperties.cpp b/storage/ndb/src/common/util/SimpleProperties.cpp
new file mode 100644
index 00000000000..00c440fcb4e
--- /dev/null
+++ b/storage/ndb/src/common/util/SimpleProperties.cpp
@@ -0,0 +1,507 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <SimpleProperties.hpp>
+#include <NdbOut.hpp>
+#include <NdbTCP.h>
+#include <UtilBuffer.hpp>
+
+bool
+SimpleProperties::Writer::first(){
+ return reset();
+}
+
+bool
+SimpleProperties::Writer::add(Uint16 key, Uint32 value){
+ Uint32 head = Uint32Value;
+ head <<= 16;
+ head += key;
+ if(!putWord(htonl(head)))
+ return false;
+
+ return putWord(htonl(value));
+}
+
+bool
+SimpleProperties::Writer::add(Uint16 key, const char * value){
+ Uint32 head = StringValue;
+ head <<= 16;
+ head += key;
+ if(!putWord(htonl(head)))
+ return false;
+ Uint32 strLen = strlen(value) + 1; // Including NULL-byte
+ if(!putWord(htonl(strLen)))
+ return false;
+
+ const Uint32 valLen = (strLen + 3) / 4;
+ return putWords((Uint32*)value, valLen);
+}
+
+bool
+SimpleProperties::Writer::add(Uint16 key, const void* value, int len){
+ Uint32 head = BinaryValue;
+ head <<= 16;
+ head += key;
+ if(!putWord(htonl(head)))
+ return false;
+ if(!putWord(htonl(len)))
+ return false;
+
+ const Uint32 valLen = (len + 3) / 4;
+ return putWords((Uint32*)value, valLen);
+}
+
+SimpleProperties::Reader::Reader(){
+ m_itemLen = 0;
+}
+
+bool
+SimpleProperties::Reader::first(){
+ reset();
+ m_itemLen = 0;
+ return readValue();
+}
+
+bool
+SimpleProperties::Reader::next(){
+ return readValue();
+}
+
+bool
+SimpleProperties::Reader::valid() const {
+ return m_type != InvalidValue;
+}
+
+Uint16
+SimpleProperties::Reader::getKey() const{
+ return m_key;
+}
+
+Uint16
+SimpleProperties::Reader::getValueLen() const {
+ switch(m_type){
+ case Uint32Value:
+ return 4;
+ case StringValue:
+ case BinaryValue:
+ return m_strLen;
+ case InvalidValue:
+ return 0;
+ }
+ return 0;
+}
+
+SimpleProperties::ValueType
+SimpleProperties::Reader::getValueType() const {
+ return m_type;
+}
+
+Uint32
+SimpleProperties::Reader::getUint32() const {
+ return m_ui32_value;
+}
+
+char *
+SimpleProperties::Reader::getString(char * dst) const {
+ if(peekWords((Uint32*)dst, m_itemLen))
+ return dst;
+ return 0;
+}
+
+bool
+SimpleProperties::Reader::readValue(){
+ if(!step(m_itemLen)){
+ m_type = InvalidValue;
+ return false;
+ }
+
+ Uint32 tmp;
+ if(!getWord(&tmp)){
+ m_type = InvalidValue;
+ return false;
+ }
+
+ tmp = ntohl(tmp);
+ m_key = tmp & 0xFFFF;
+ m_type = (SimpleProperties::ValueType)(tmp >> 16);
+ switch(m_type){
+ case Uint32Value:
+ m_itemLen = 1;
+ if(!peekWord(&m_ui32_value))
+ return false;
+ m_ui32_value = ntohl(m_ui32_value);
+ return true;
+ case StringValue:
+ case BinaryValue:
+ if(!getWord(&tmp))
+ return false;
+ m_strLen = ntohl(tmp);
+ m_itemLen = (m_strLen + 3)/4;
+ return true;
+ default:
+ m_itemLen = 0;
+ m_type = InvalidValue;
+ return false;
+ }
+}
+
+SimpleProperties::UnpackStatus
+SimpleProperties::unpack(Reader & it, void * dst,
+ const SP2StructMapping _map[], Uint32 mapSz,
+ bool ignoreMinMax,
+ bool ignoreUnknownKeys){
+ do {
+ if(!it.valid())
+ break;
+
+ bool found = false;
+ Uint16 key = it.getKey();
+ for(Uint32 i = 0; i<mapSz; i++){
+ if(key == _map[i].Key){
+ found = true;
+ if(_map[i].Type == InvalidValue)
+ return Break;
+ if(_map[i].Type != it.getValueType())
+ return TypeMismatch;
+
+ char * _dst = (char *)dst;
+ _dst += _map[i].Offset;
+
+ switch(it.getValueType()){
+ case Uint32Value:{
+ const Uint32 val = it.getUint32();
+ if(!ignoreMinMax){
+ if(val < _map[i].minValue)
+ return ValueTooLow;
+ if(val > _map[i].maxValue)
+ return ValueTooHigh;
+ }
+ * ((Uint32 *)_dst) = val;
+ break;
+ }
+ case BinaryValue:
+ case StringValue:{
+ unsigned len = it.getValueLen();
+ if(len < _map[i].minValue)
+ return ValueTooLow;
+ if(len > _map[i].maxValue)
+ return ValueTooHigh;
+ it.getString(_dst);
+ break;
+ }
+ default:
+ abort();
+ }
+ break;
+ }
+ }
+ if(!found && !ignoreUnknownKeys)
+ return UnknownKey;
+ } while(it.next());
+
+ return Eof;
+}
+
+SimpleProperties::UnpackStatus
+SimpleProperties::pack(Writer & it, const void * __src,
+ const SP2StructMapping _map[], Uint32 mapSz,
+ bool ignoreMinMax){
+
+ const char * _src = (const char *)__src;
+
+ for(Uint32 i = 0; i<mapSz; i++){
+ bool ok = false;
+ const char * src = _src + _map[i].Offset;
+ switch(_map[i].Type){
+ case SimpleProperties::InvalidValue:
+ ok = true;
+ break;
+ case SimpleProperties::Uint32Value:{
+ Uint32 val = * ((Uint32*)src);
+ if(!ignoreMinMax){
+ if(val < _map[i].minValue)
+ return ValueTooLow;
+ if(val > _map[i].maxValue)
+ return ValueTooHigh;
+ }
+ ok = it.add(_map[i].Key, val);
+ }
+ break;
+ case SimpleProperties::BinaryValue:{
+ const char * src_len = _src + _map[i].Length_Offset;
+ Uint32 len = *((Uint32*)src_len);
+ if(!ignoreMinMax){
+ if(len == _map[i].maxValue)
+ return ValueTooHigh;
+ }
+ ok = it.add(_map[i].Key, src, len);
+ break;
+ }
+ case SimpleProperties::StringValue:
+ if(!ignoreMinMax){
+ size_t len = strlen(src);
+ if(len == _map[i].maxValue)
+ return ValueTooHigh;
+ }
+ ok = it.add(_map[i].Key, src);
+ break;
+ }
+ if(!ok)
+ return OutOfMemory;
+ }
+
+ return Eof;
+}
+
+void
+SimpleProperties::Reader::printAll(NdbOut& ndbout){
+ char tmp[1024];
+ for(first(); valid(); next()){
+ switch(getValueType()){
+ case SimpleProperties::Uint32Value:
+ ndbout << "Key: " << getKey()
+ << " value(" << getValueLen() << ") : "
+ << getUint32() << endl;
+ break;
+ case SimpleProperties::BinaryValue:
+ case SimpleProperties::StringValue:
+ if(getValueLen() < 1024){
+ getString(tmp);
+ ndbout << "Key: " << getKey()
+ << " value(" << getValueLen() << ") : "
+ << "\"" << tmp << "\"" << endl;
+ } else {
+ ndbout << "Key: " << getKey()
+ << " value(" << getValueLen() << ") : "
+ << "\"" << "<TOO LONG>" << "\"" << endl;
+
+ }
+ break;
+ default:
+ ndbout << "Unknown type for key: " << getKey()
+ << " type: " << (Uint32)getValueType() << endl;
+ }
+ }
+}
+
+SimplePropertiesLinearReader::SimplePropertiesLinearReader
+(const Uint32 * src, Uint32 len){
+ m_src = src;
+ m_len = len;
+ m_pos = 0;
+ first();
+}
+
+void
+SimplePropertiesLinearReader::reset() {
+ m_pos = 0;
+}
+
+bool
+SimplePropertiesLinearReader::step(Uint32 len){
+ m_pos += len;
+ return m_pos < m_len;
+}
+
+bool
+SimplePropertiesLinearReader::getWord(Uint32 * dst) {
+ if(m_pos<m_len){
+ * dst = m_src[m_pos++];
+ return true;
+ }
+ return false;
+}
+
+bool
+SimplePropertiesLinearReader::peekWord(Uint32 * dst) const {
+ if(m_pos<m_len){
+ * dst = m_src[m_pos];
+ return true;
+ }
+ return false;
+}
+
+bool
+SimplePropertiesLinearReader::peekWords(Uint32 * dst, Uint32 len) const {
+ if(m_pos + len <= m_len){
+ memcpy(dst, &m_src[m_pos], 4 * len);
+ return true;
+ }
+ return false;
+}
+
+LinearWriter::LinearWriter(Uint32 * src, Uint32 len){
+ m_src = src;
+ m_len = len;
+ reset();
+}
+
+bool LinearWriter::reset() { m_pos = 0; return m_len > 0;}
+
+bool
+LinearWriter::putWord(Uint32 val){
+ if(m_pos < m_len){
+ m_src[m_pos++] = val;
+ return true;
+ }
+ return false;
+}
+
+bool
+LinearWriter::putWords(const Uint32 * src, Uint32 len){
+ if(m_pos + len <= m_len){
+ memcpy(&m_src[m_pos], src, 4 * len);
+ m_pos += len;
+ return true;
+ }
+ return false;
+}
+
+Uint32
+LinearWriter::getWordsUsed() const { return m_pos;}
+
+UtilBufferWriter::UtilBufferWriter(UtilBuffer & b)
+ : m_buf(b)
+{
+ reset();
+}
+
+bool UtilBufferWriter::reset() { m_buf.clear(); return true;}
+
+bool
+UtilBufferWriter::putWord(Uint32 val){
+ return (m_buf.append(&val, 4) == 0);
+}
+
+bool
+UtilBufferWriter::putWords(const Uint32 * src, Uint32 len){
+ return (m_buf.append(src, 4 * len) == 0);
+}
+
+Uint32
+UtilBufferWriter::getWordsUsed() const { return m_buf.length() / 4;}
+
+#if 0
+LinearPagesReader::LinearPagesReader(const Uint32 * base,
+ Uint32 pageSize,
+ Uint32 headerSize,
+ Uint32 noOfPages,
+ Uint32 len){
+ m_base = base;
+ m_pageSz = pageSize;
+ m_noOfPages = noOfPages;
+ m_pageHeaderSz = headerSize;
+ m_len = len;
+ reset();
+}
+
+void
+LinearPagesReader::reset() { m_pos = 0;}
+
+bool
+LinearPagesReader::step(Uint32 len){
+ m_pos += len;
+ return m_pos < m_len;
+}
+
+bool
+LinearPagesReader::getWord(Uint32 * dst) {
+ if(m_pos<m_len){
+ * dst = m_base[getPos(m_pos++)];
+ return true;
+ }
+ return false;
+}
+
+bool
+LinearPagesReader::peekWord(Uint32 * dst) const {
+ if(m_pos<m_len){
+ * dst = m_base[getPos(m_pos)];
+ return true;
+ }
+ return false;
+}
+
+bool
+LinearPagesReader::peekWords(Uint32 * dst, Uint32 len) const {
+ if(m_pos + len <= m_len){
+ for(Uint32 i = 0; i<len; i++)
+ * (dst + i) = m_base[getPos(m_pos + i)];
+ return true;
+ }
+ return false;
+}
+
+Uint32
+LinearPagesReader::getPos(Uint32 pos) const {
+ const Uint32 sz = (m_pageSz - m_pageHeaderSz);
+ Uint32 no = pos / sz;
+ Uint32 in = pos % sz;
+ return no * m_pageSz + m_pageHeaderSz + in;
+}
+
+LinearPagesWriter::LinearPagesWriter(Uint32 * base,
+ Uint32 pageSize,
+ Uint32 noOfPages,
+ Uint32 headerSize){
+ m_base = base;
+ m_pageSz = pageSize;
+ m_noOfPages = noOfPages;
+ m_pageHeaderSz = headerSize;
+ m_len = noOfPages * (pageSize - headerSize);
+ reset();
+}
+
+bool
+LinearPagesWriter::putWord(Uint32 val){
+ if(m_pos < m_len){
+ m_base[getPos(m_pos++)] = val;
+ return true;
+ }
+ return false;
+}
+
+bool
+LinearPagesWriter::putWords(const Uint32 * src, Uint32 len){
+ if(m_pos + len <= m_len){
+ for(Uint32 i = 0; i<len; i++)
+ m_base[getPos(m_pos++)] = src[i];
+ return true;
+ }
+ return false;
+}
+
+#if 0
+Uint32
+LinearPagesWriter::getWordsUsed() const {
+ return getPos(m_pos);
+}
+#endif
+
+Uint32
+LinearPagesWriter::getPagesUsed() const {
+ return m_pos / (m_pageSz - m_pageHeaderSz);
+}
+
+Uint32
+LinearPagesWriter::getPos(Uint32 pos) const {
+ const Uint32 sz = (m_pageSz - m_pageHeaderSz);
+ Uint32 no = pos / sz;
+ Uint32 in = pos % sz;
+ return no * m_pageSz + m_pageHeaderSz + in;
+}
+#endif
diff --git a/storage/ndb/src/common/util/SocketAuthenticator.cpp b/storage/ndb/src/common/util/SocketAuthenticator.cpp
new file mode 100644
index 00000000000..aed4db39231
--- /dev/null
+++ b/storage/ndb/src/common/util/SocketAuthenticator.cpp
@@ -0,0 +1,91 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+
+#include <SocketClient.hpp>
+#include <SocketAuthenticator.hpp>
+#include <InputStream.hpp>
+#include <OutputStream.hpp>
+#include <NdbOut.hpp>
+
+SocketAuthSimple::SocketAuthSimple(const char *username, const char *passwd) {
+ if (username)
+ m_username= strdup(username);
+ else
+ m_username= 0;
+ if (passwd)
+ m_passwd= strdup(passwd);
+ else
+ m_passwd= 0;
+}
+
+SocketAuthSimple::~SocketAuthSimple()
+{
+ if (m_passwd)
+ free((void*)m_passwd);
+ if (m_username)
+ free((void*)m_username);
+}
+
+bool SocketAuthSimple::client_authenticate(int sockfd)
+{
+ SocketOutputStream s_output(sockfd);
+ SocketInputStream s_input(sockfd);
+
+ if (m_username)
+ s_output.println("%s", m_username);
+ else
+ s_output.println("");
+
+ if (m_passwd)
+ s_output.println("%s", m_passwd);
+ else
+ s_output.println("");
+
+ char buf[16];
+ if (s_input.gets(buf, 16) == 0) return false;
+ if (strncmp("ok", buf, 2) == 0)
+ return true;
+
+ return false;
+}
+
+bool SocketAuthSimple::server_authenticate(int sockfd)
+{
+
+ SocketOutputStream s_output(sockfd);
+ SocketInputStream s_input(sockfd);
+
+ char buf[256];
+
+ if (s_input.gets(buf, 256) == 0) return false;
+ buf[255]= 0;
+ if (m_username)
+ free((void*)m_username);
+ m_username= strdup(buf);
+
+ if (s_input.gets(buf, 256) == 0) return false;
+ buf[255]= 0;
+ if (m_passwd)
+ free((void*)m_passwd);
+ m_passwd= strdup(buf);
+
+ s_output.println("ok");
+
+ return true;
+}
diff --git a/storage/ndb/src/common/util/SocketClient.cpp b/storage/ndb/src/common/util/SocketClient.cpp
new file mode 100644
index 00000000000..38df1417eb8
--- /dev/null
+++ b/storage/ndb/src/common/util/SocketClient.cpp
@@ -0,0 +1,94 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+#include <NdbOut.hpp>
+
+#include <SocketClient.hpp>
+#include <SocketAuthenticator.hpp>
+
+SocketClient::SocketClient(const char *server_name, unsigned short port, SocketAuthenticator *sa)
+{
+ m_auth= sa;
+ m_port= port;
+ m_server_name= strdup(server_name);
+ m_sockfd= NDB_INVALID_SOCKET;
+}
+
+SocketClient::~SocketClient()
+{
+ if (m_server_name)
+ free(m_server_name);
+ if (m_sockfd != NDB_INVALID_SOCKET)
+ NDB_CLOSE_SOCKET(m_sockfd);
+ if (m_auth)
+ delete m_auth;
+}
+
+bool
+SocketClient::init()
+{
+ if (m_sockfd != NDB_INVALID_SOCKET)
+ NDB_CLOSE_SOCKET(m_sockfd);
+
+ memset(&m_servaddr, 0, sizeof(m_servaddr));
+ m_servaddr.sin_family = AF_INET;
+ m_servaddr.sin_port = htons(m_port);
+ // Convert ip address presentation format to numeric format
+ if (Ndb_getInAddr(&m_servaddr.sin_addr, m_server_name))
+ return false;
+
+ m_sockfd= socket(AF_INET, SOCK_STREAM, 0);
+ if (m_sockfd == NDB_INVALID_SOCKET) {
+ return false;
+ }
+
+ return true;
+}
+
+NDB_SOCKET_TYPE
+SocketClient::connect()
+{
+ if (m_sockfd == NDB_INVALID_SOCKET)
+ {
+ if (!init()) {
+#ifdef VM_TRACE
+ ndbout << "SocketClient::connect() failed " << m_server_name << " " << m_port << endl;
+#endif
+ return NDB_INVALID_SOCKET;
+ }
+ }
+ const int r = ::connect(m_sockfd, (struct sockaddr*) &m_servaddr, sizeof(m_servaddr));
+ if (r == -1) {
+ NDB_CLOSE_SOCKET(m_sockfd);
+ m_sockfd= NDB_INVALID_SOCKET;
+ return NDB_INVALID_SOCKET;
+ }
+
+ if (m_auth) {
+ if (!m_auth->client_authenticate(m_sockfd))
+ {
+ NDB_CLOSE_SOCKET(m_sockfd);
+ m_sockfd= NDB_INVALID_SOCKET;
+ return NDB_INVALID_SOCKET;
+ }
+ }
+ NDB_SOCKET_TYPE sockfd= m_sockfd;
+ m_sockfd= NDB_INVALID_SOCKET;
+
+ return sockfd;
+}
diff --git a/storage/ndb/src/common/util/SocketServer.cpp b/storage/ndb/src/common/util/SocketServer.cpp
new file mode 100644
index 00000000000..6019d24d736
--- /dev/null
+++ b/storage/ndb/src/common/util/SocketServer.cpp
@@ -0,0 +1,345 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+#include <my_pthread.h>
+
+#include <SocketServer.hpp>
+
+#include <NdbTCP.h>
+#include <NdbOut.hpp>
+#include <NdbThread.h>
+#include <NdbSleep.h>
+
+#define DEBUG(x) ndbout << x << endl;
+
+SocketServer::SocketServer(int maxSessions) :
+ m_sessions(10),
+ m_services(5)
+{
+ m_thread = 0;
+ m_stopThread = false;
+ m_maxSessions = maxSessions;
+}
+
+SocketServer::~SocketServer() {
+ unsigned i;
+ for(i = 0; i<m_sessions.size(); i++){
+ delete m_sessions[i].m_session;
+ }
+ for(i = 0; i<m_services.size(); i++){
+ delete m_services[i].m_service;
+ }
+}
+
+bool
+SocketServer::tryBind(unsigned short port, const char * intface) {
+ struct sockaddr_in servaddr;
+ memset(&servaddr, 0, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(port);
+
+ if(intface != 0){
+ if(Ndb_getInAddr(&servaddr.sin_addr, intface))
+ return false;
+ }
+
+ const NDB_SOCKET_TYPE sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == NDB_INVALID_SOCKET) {
+ return false;
+ }
+
+ const int on = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (const char*)&on, sizeof(on)) == -1) {
+ NDB_CLOSE_SOCKET(sock);
+ return false;
+ }
+
+ if (bind(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) {
+ NDB_CLOSE_SOCKET(sock);
+ return false;
+ }
+
+ NDB_CLOSE_SOCKET(sock);
+ return true;
+}
+
+bool
+SocketServer::setup(SocketServer::Service * service,
+ unsigned short * port,
+ const char * intface){
+ DBUG_ENTER("SocketServer::setup");
+ DBUG_PRINT("enter",("interface=%s, port=%u", intface, *port));
+ struct sockaddr_in servaddr;
+ memset(&servaddr, 0, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(*port);
+
+ if(intface != 0){
+ if(Ndb_getInAddr(&servaddr.sin_addr, intface))
+ DBUG_RETURN(false);
+ }
+
+ const NDB_SOCKET_TYPE sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == NDB_INVALID_SOCKET) {
+ DBUG_PRINT("error",("socket() - %d - %s",
+ errno, strerror(errno)));
+ DBUG_RETURN(false);
+ }
+
+ const int on = 1;
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (const char*)&on, sizeof(on)) == -1) {
+ DBUG_PRINT("error",("getsockopt() - %d - %s",
+ errno, strerror(errno)));
+ NDB_CLOSE_SOCKET(sock);
+ DBUG_RETURN(false);
+ }
+
+ if (bind(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) == -1) {
+ DBUG_PRINT("error",("bind() - %d - %s",
+ errno, strerror(errno)));
+ NDB_CLOSE_SOCKET(sock);
+ DBUG_RETURN(false);
+ }
+
+ /* Get the port we bound to */
+ SOCKET_SIZE_TYPE sock_len = sizeof(servaddr);
+ if(getsockname(sock,(struct sockaddr*)&servaddr,&sock_len)<0) {
+ ndbout_c("An error occurred while trying to find out what"
+ " port we bound to. Error: %s",strerror(errno));
+ NDB_CLOSE_SOCKET(sock);
+ DBUG_RETURN(false);
+ }
+
+ DBUG_PRINT("info",("bound to %u",ntohs(servaddr.sin_port)));
+ if (listen(sock, m_maxSessions) == -1){
+ DBUG_PRINT("error",("listen() - %d - %s",
+ errno, strerror(errno)));
+ NDB_CLOSE_SOCKET(sock);
+ DBUG_RETURN(false);
+ }
+
+ ServiceInstance i;
+ i.m_socket = sock;
+ i.m_service = service;
+ m_services.push_back(i);
+
+ *port = ntohs(servaddr.sin_port);
+
+ DBUG_RETURN(true);
+}
+
+void
+SocketServer::doAccept(){
+ fd_set readSet, exceptionSet;
+ FD_ZERO(&readSet);
+ FD_ZERO(&exceptionSet);
+
+ m_services.lock();
+ int maxSock = 0;
+ for (unsigned i = 0; i < m_services.size(); i++){
+ const NDB_SOCKET_TYPE s = m_services[i].m_socket;
+ FD_SET(s, &readSet);
+ FD_SET(s, &exceptionSet);
+ maxSock = (maxSock > s ? maxSock : s);
+ }
+ struct timeval timeout;
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ if(select(maxSock + 1, &readSet, 0, &exceptionSet, &timeout) > 0){
+ for (unsigned i = 0; i < m_services.size(); i++){
+ ServiceInstance & si = m_services[i];
+
+ if(FD_ISSET(si.m_socket, &readSet)){
+ NDB_SOCKET_TYPE childSock = accept(si.m_socket, 0, 0);
+ if(childSock == NDB_INVALID_SOCKET){
+ continue;
+ }
+
+ SessionInstance s;
+ s.m_service = si.m_service;
+ s.m_session = si.m_service->newSession(childSock);
+ if(s.m_session != 0){
+ m_sessions.push_back(s);
+ startSession(m_sessions.back());
+ }
+
+ continue;
+ }
+
+ if(FD_ISSET(si.m_socket, &exceptionSet)){
+ DEBUG("socket in the exceptionSet");
+ continue;
+ }
+ }
+ }
+ m_services.unlock();
+}
+
+extern "C"
+void*
+socketServerThread_C(void* _ss){
+ SocketServer * ss = (SocketServer *)_ss;
+ ss->doRun();
+ return 0;
+}
+
+void
+SocketServer::startServer(){
+ m_threadLock.lock();
+ if(m_thread == 0 && m_stopThread == false){
+ m_thread = NdbThread_Create(socketServerThread_C,
+ (void**)this,
+ 32768,
+ "NdbSockServ",
+ NDB_THREAD_PRIO_LOW);
+ }
+ m_threadLock.unlock();
+}
+
+void
+SocketServer::stopServer(){
+ m_threadLock.lock();
+ if(m_thread != 0){
+ m_stopThread = true;
+
+ void * res;
+ NdbThread_WaitFor(m_thread, &res);
+ NdbThread_Destroy(&m_thread);
+ m_thread = 0;
+ }
+ m_threadLock.unlock();
+}
+
+void
+SocketServer::doRun(){
+
+ while(!m_stopThread){
+ checkSessions();
+ if(m_sessions.size() < m_maxSessions){
+ doAccept();
+ } else {
+ NdbSleep_MilliSleep(200);
+ }
+ }
+}
+
+void
+SocketServer::startSession(SessionInstance & si){
+ si.m_thread = NdbThread_Create(sessionThread_C,
+ (void**)si.m_session,
+ 32768,
+ "NdbSock_Session",
+ NDB_THREAD_PRIO_LOW);
+}
+
+static
+bool
+transfer(NDB_SOCKET_TYPE sock){
+#if defined NDB_OSE || defined NDB_SOFTOSE
+ const PROCESS p = current_process();
+ const size_t ps = sizeof(PROCESS);
+ int res = setsockopt(sock, SOL_SOCKET, SO_OSEOWNER, &p, ps);
+ if(res != 0){
+ ndbout << "Failed to transfer ownership of socket" << endl;
+ return false;
+ }
+#endif
+ return true;
+}
+
+void
+SocketServer::foreachSession(void (*func)(SocketServer::Session*, void *), void *data)
+{
+ for(int i = m_sessions.size() - 1; i >= 0; i--){
+ (*func)(m_sessions[i].m_session, data);
+ }
+ checkSessions();
+}
+
+void
+SocketServer::checkSessions(){
+ for(int i = m_sessions.size() - 1; i >= 0; i--){
+ if(m_sessions[i].m_session->m_stopped){
+ if(m_sessions[i].m_thread != 0){
+ void* ret;
+ NdbThread_WaitFor(m_sessions[i].m_thread, &ret);
+ NdbThread_Destroy(&m_sessions[i].m_thread);
+ }
+ m_sessions[i].m_session->stopSession();
+ delete m_sessions[i].m_session;
+ m_sessions.erase(i);
+ }
+ }
+}
+
+void
+SocketServer::stopSessions(bool wait){
+ int i;
+ for(i = m_sessions.size() - 1; i>=0; i--)
+ {
+ m_sessions[i].m_session->stopSession();
+ m_sessions[i].m_session->m_stop = true; // to make sure
+ }
+ for(i = m_services.size() - 1; i>=0; i--)
+ m_services[i].m_service->stopSessions();
+
+ if(wait){
+ while(m_sessions.size() > 0){
+ checkSessions();
+ NdbSleep_MilliSleep(100);
+ }
+ }
+}
+
+/***** Session code ******/
+
+extern "C"
+void*
+sessionThread_C(void* _sc){
+ SocketServer::Session * si = (SocketServer::Session *)_sc;
+
+ if(!transfer(si->m_socket)){
+ si->m_stopped = true;
+ return 0;
+ }
+
+ /**
+ * may have m_stopped set if we're transforming a mgm
+ * connection into a transporter connection.
+ */
+ if(!si->m_stopped)
+ {
+ if(!si->m_stop){
+ si->m_stopped = false;
+ si->runSession();
+ } else {
+ NDB_CLOSE_SOCKET(si->m_socket);
+ }
+ }
+
+ si->m_stopped = true;
+ return 0;
+}
+
+template class MutexVector<SocketServer::ServiceInstance>;
+template class MutexVector<SocketServer::SessionInstance>;
diff --git a/storage/ndb/src/common/util/basestring_vsnprintf.c b/storage/ndb/src/common/util/basestring_vsnprintf.c
new file mode 100644
index 00000000000..f5d01fb1532
--- /dev/null
+++ b/storage/ndb/src/common/util/basestring_vsnprintf.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifdef __sgi
+/* define on IRIX to get posix compliant vsnprintf */
+#define _XOPEN_SOURCE 500
+#endif
+#include <stdio.h>
+#include <basestring_vsnprintf.h>
+#include <my_config.h>
+
+#ifdef _WINDOWS
+#define SNPRINTF_RETURN_TRUNC
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#endif
+
+int
+basestring_snprintf(char *str, size_t size, const char *format, ...)
+{
+ int ret;
+ va_list ap;
+ va_start(ap, format);
+ ret= basestring_vsnprintf(str, size, format, ap);
+ va_end(ap);
+ return(ret);
+}
+
+#ifdef SNPRINTF_RETURN_TRUNC
+static char basestring_vsnprintf_buf[16*1024];
+#endif
+int
+basestring_vsnprintf(char *str, size_t size, const char *format, va_list ap)
+{
+ if (size == 0)
+ {
+#ifdef SNPRINTF_RETURN_TRUNC
+ return vsnprintf(basestring_vsnprintf_buf,
+ sizeof(basestring_vsnprintf_buf),
+ format, ap);
+#else
+ char buf[1];
+ return vsnprintf(buf, 1, format, ap);
+#endif
+ }
+ {
+ int ret= vsnprintf(str, size, format, ap);
+#ifdef SNPRINTF_RETURN_TRUNC
+ if (ret == size-1 || ret == -1)
+ {
+ ret= vsnprintf(basestring_vsnprintf_buf,
+ sizeof(basestring_vsnprintf_buf),
+ format, ap);
+ }
+#endif
+ return ret;
+ }
+}
diff --git a/storage/ndb/src/common/util/filetest/FileUnitTest.cpp b/storage/ndb/src/common/util/filetest/FileUnitTest.cpp
new file mode 100644
index 00000000000..b6e7b7e8ec0
--- /dev/null
+++ b/storage/ndb/src/common/util/filetest/FileUnitTest.cpp
@@ -0,0 +1,237 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "FileUnitTest.hpp"
+#include <File.hpp>
+
+#include <NdbOut.hpp>
+
+typedef bool (*TESTFUNC)(const char*);
+
+typedef const char TESTNAME;
+typedef struct
+{
+ const char* name;
+ TESTFUNC test;
+}Tests;
+
+static Tests testCases[] = { {"Create/Write", &FileUnitTest::testWrite},
+ {"Read", &FileUnitTest::testRead},
+ {"Exists", &FileUnitTest::testExists},
+ {"File Size", &FileUnitTest::testSize},
+ {"Rename", &FileUnitTest::testRename},
+ {"Remove", &FileUnitTest::testRemove} };
+
+static int testFailed = 0;
+
+int main(int argc, char* argv[])
+{
+ if (argc < 2)
+ {
+ ndbout << "Usage: filetest <filename>" << endl;
+ return 0;
+ }
+ const char* fileName = argv[1];
+
+ int testCount = (sizeof(testCases) / sizeof(Tests));
+ ndbout << "Starting " << testCount << " tests..." << endl;
+ for (int i = 0; i < testCount; i++)
+ {
+ ndbout << "-- " << " Test " << i + 1
+ << " [" << testCases[i].name << "] --" << endl;
+ if (testCases[i].test(fileName))
+ {
+ ndbout << "-- Passed --" << endl;
+ }
+ else
+ {
+ ndbout << "-- Failed -- " << endl;
+ }
+
+ }
+ ndbout << endl << "-- " << testCount - testFailed << " passed, "
+ << testFailed << " failed --" << endl;
+ return 0;
+}
+
+
+bool
+FileUnitTest::testWrite(const char* aFileName)
+{
+ bool rc = true;
+ File f;
+ if (f.open(aFileName, "w"))
+ {
+ f.writeChar("ABABABABABAB ABBABAB ABBABA ABAB JKH KJHA JHHAHAH...");
+ f.writeChar("12129791242 1298371923 912738912 378129837128371128132...\n");
+ f.close();
+ }
+ else
+ {
+ error("testWrite failed: ");
+ rc = false;
+ }
+ return rc;
+}
+
+bool
+FileUnitTest::testRead(const char* aFileName)
+{
+ bool rc = true;
+ // Read file
+ File f;
+ if (f.open(aFileName, "r"))
+ {
+ long size = f.size();
+ ndbout << "File size = " << size << endl;
+ ndbout << "Allocating buf of " << size << " bytes" << endl;
+ char* buf = new char[size];
+ buf[size - 1] = '\0';
+ int r = 0;
+ while ((r = f.readChar(buf, r, size)) > 0)
+ {
+ ndbout << "Read(" << r << "):" << buf << endl;
+ }
+ f.close();
+ delete buf;
+ }
+ else
+ {
+ error("readTest failed: ");
+ rc = false;
+ }
+ return rc;
+}
+
+bool
+FileUnitTest::testExists(const char* aFileName)
+{
+ bool rc = true;
+ if (File::exists(aFileName))
+ {
+ if (File::exists("ThisFileShouldnotbe.txt"))
+ {
+ rc = false;
+ error("testExists failed, the file should NOT be found.");
+ }
+ }
+ else
+ {
+ rc = false;
+ error("testExists failed, the file should exist.");
+ }
+
+ return rc;
+}
+
+
+bool
+FileUnitTest::testSize(const char* aFileName)
+{
+ bool rc = true;
+ File f;
+ if (f.open(aFileName, "r"))
+ {
+ long size = f.size();
+ if (size <= 0)
+ {
+ rc = false;
+ error("testSize failed, size is <= 0");
+ }
+ ndbout << "File size = " << size << endl;
+ }
+ else
+ {
+ rc = false;
+ error("testSize failed, could no open file.");
+ }
+ f.close();
+ return rc;
+}
+
+bool
+FileUnitTest::testRename(const char* aFileName)
+{
+ bool rc = true;
+ if (File::rename(aFileName, "filetest_new.txt"))
+ {
+ if (!File::exists("filetest_new.txt"))
+ {
+ rc = false;
+ error("testRename failed, new file does not exists.");
+ }
+ else
+ {
+ ndbout << "Renamed " << aFileName << " to filetest_new.txt" << endl;
+ }
+ }
+ else
+ {
+ rc = false;
+ error("testRename failed, unable to rename file.");
+ }
+
+ return rc;
+}
+
+bool
+FileUnitTest::testRemove(const char* aFileName)
+{
+ bool rc = true;
+ File f;
+ if (f.open("filetest_new.txt", "r"))
+ {
+ if (!f.remove())
+ {
+ rc = false;
+ error("testRemove failed, could not remove file.");
+ }
+ else
+ {
+ if (File::exists("filetest_new"))
+ {
+ rc = false;
+ error("testRemove failed, file was not removed, it still exists.");
+ }
+ }
+ } // (f.open("filetest_new", "r"))
+ else
+ {
+ rc = false;
+ error("testRemove failed, could not read the file.");
+ }
+
+ return rc;
+}
+
+void
+FileUnitTest::error(const char* msg)
+{
+ testFailed++;
+ ndbout << "Test failed: " << msg << endl;
+ perror("Errno msg");
+}
+
+
+FileUnitTest::FileUnitTest()
+{
+
+}
+
+FileUnitTest::~FileUnitTest()
+{
+
+}
diff --git a/storage/ndb/src/common/util/filetest/FileUnitTest.hpp b/storage/ndb/src/common/util/filetest/FileUnitTest.hpp
new file mode 100644
index 00000000000..a589615e9b2
--- /dev/null
+++ b/storage/ndb/src/common/util/filetest/FileUnitTest.hpp
@@ -0,0 +1,41 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef FILEUNITTEST_H
+#define FILEUNITTEST_H
+
+/**
+ * Unit test of File.
+ *
+ * @version #@ $Id: FileUnitTest.hpp,v 1.1 2002/03/13 18:09:03 eyualex Exp $
+ */
+class FileUnitTest
+{
+public:
+ static bool testWrite(const char* aFileName);
+ static bool testRead(const char* aFileName);
+ static bool testExists(const char* aFileName);
+ static bool testSize(const char* aFileName);
+ static bool testRename(const char* aFileName);
+ static bool testRemove(const char* aFileName);
+
+ static void error(const char* msg);
+private:
+ FileUnitTest();
+ ~FileUnitTest();
+
+};
+#endif
diff --git a/storage/ndb/src/common/util/filetest/Makefile b/storage/ndb/src/common/util/filetest/Makefile
new file mode 100644
index 00000000000..fe1842921f9
--- /dev/null
+++ b/storage/ndb/src/common/util/filetest/Makefile
@@ -0,0 +1,14 @@
+include .defs.mk
+
+TYPE :=
+
+BIN_TARGET := filetest
+BIN_TARGET_ARCHIVES := portlib general
+
+SOURCES := FileUnitTest.cpp
+
+CCFLAGS_LOC += -I$(NDB_TOP)/include/logger -I$(NDB_TOP)/include/portlib
+
+include $(NDB_TOP)/Epilogue.mk
+
+
diff --git a/storage/ndb/src/common/util/getarg.cat3 b/storage/ndb/src/common/util/getarg.cat3
new file mode 100644
index 00000000000..31685510537
--- /dev/null
+++ b/storage/ndb/src/common/util/getarg.cat3
@@ -0,0 +1,237 @@
+GETARG(3) OpenBSD Programmer's Manual GETARG(3)
+
+NNAAMMEE
+ ggeettaarrgg, aarrgg__pprriinnttuussaaggee - collect command line options
+
+SSYYNNOOPPSSIISS
+ ##iinncclluuddee <<ggeettaarrgg..hh>>
+
+
+ _i_n_t
+ ggeettaarrgg(_s_t_r_u_c_t _g_e_t_a_r_g_s _*_a_r_g_s, _s_i_z_e___t _n_u_m___a_r_g_s, _i_n_t _a_r_g_c, _c_h_a_r _*_*_a_r_g_v,
+ _i_n_t _*_o_p_t_i_n_d);
+
+
+ _v_o_i_d
+ aarrgg__pprriinnttuussaaggee(_s_t_r_u_c_t _g_e_t_a_r_g_s _*_a_r_g_s, _s_i_z_e___t _n_u_m___a_r_g_s,
+ _c_o_n_s_t _c_h_a_r _*_p_r_o_g_n_a_m_e, _c_o_n_s_t _c_h_a_r _*_e_x_t_r_a___s_t_r_i_n_g);
+
+
+DDEESSCCRRIIPPTTIIOONN
+ ggeettaarrgg() collects any command line options given to a program in an easi­
+ ly used way. aarrgg__pprriinnttuussaaggee() pretty-prints the available options, with
+ a short help text.
+
+ _a_r_g_s is the option specification to use, and it's an array of _s_t_r_u_c_t
+ _g_e_t_a_r_g_s elements. _n_u_m___a_r_g_s is the size of _a_r_g_s (in elements). _a_r_g_c and
+ _a_r_g_v are the argument count and argument vector to extract option from.
+ _o_p_t_i_n_d is a pointer to an integer where the index to the last processed
+ argument is stored, it must be initialised to the first index (minus one)
+ to process (normally 0) before the first call.
+
+ _a_r_g___p_r_i_n_t_u_s_a_g_e take the same _a_r_g_s and _n_u_m___a_r_g_s as getarg; _p_r_o_g_n_a_m_e _i_s _t_h_e
+ _n_a_m_e _o_f _t_h_e _p_r_o_g_r_a_m _(_t_o _b_e progname0 _0progname1 _1progname2 _2progname3
+ _3progname4 _4progname5 _e_x_t_r_a___s_t_r_i_n_g is a string to print after the actual
+ options to indicate more arguments. The usefulness of this function is
+ realised only be people who has used programs that has help strings that
+ doesn't match what the code does.
+
+ The _g_e_t_a_r_g_s struct has the following elements.
+
+
+ struct getargs{
+ const char *long_name;
+ char short_name;
+ enum { arg_integer,
+ arg_string,
+ arg_flag,
+ arg_negative_flag,
+ arg_strings,
+ arg_double,
+ arg_collect
+ } type;
+ void *value;
+ const char *help;
+ const char *arg_help;
+ };
+
+ _l_o_n_g___n_a_m_e is the long name of the option, it can be NULL, if you don't
+ want a long name. _s_h_o_r_t___n_a_m_e is the characted to use as short option, it
+ can be zero. If the option has a value the _v_a_l_u_e field gets filled in
+ with that value interpreted as specified by the _t_y_p_e field. _h_e_l_p is a
+ longer help string for the option as a whole, if it's NULL the help text
+ for the option is omitted (but it's still displayed in the synopsis).
+ _a_r_g___h_e_l_p is a description of the argument, if NULL a default value will
+ be used, depending on the type of the option:
+
+
+ arg_integer the argument is a signed integer, and _v_a_l_u_e should
+ point to an _i_n_t.
+
+ _a_r_g___s_t_r_i_n_g the argument is a string, and _v_a_l_u_e should point to a
+ _c_h_a_r_*.
+
+ _a_r_g___f_l_a_g the argument is a flag, and _v_a_l_u_e should point to a
+ _i_n_t. It gets filled in with either zero or one, de­
+ pending on how the option is given, the normal case
+ beeing one. Note that if the option isn't given, the
+ value isn't altered, so it should be initialised to
+ some useful default.
+
+ _a_r_g___n_e_g_a_t_i_v_e___f_l_a_g this is the same as _a_r_g___f_l_a_g but it reverses the mean­
+ ing of the flag (a given short option clears the
+ flag), and the synopsis of a long option is negated.
+
+ _a_r_g___s_t_r_i_n_g_s the argument can be given multiple times, and the val­
+ ues are collected in an array; _v_a_l_u_e should be a
+ pointer to a _s_t_r_u_c_t _g_e_t_a_r_g___s_t_r_i_n_g_s structure, which
+ holds a length and a string pointer.
+
+ _a_r_g___d_o_u_b_l_e argument is a double precision floating point value,
+ and _v_a_l_u_e should point to a _d_o_u_b_l_e.
+
+ _a_r_g___c_o_l_l_e_c_t allows more fine-grained control of the option parsing
+ process. _v_a_l_u_e should be a pointer to a
+ _g_e_t_a_r_g___c_o_l_l_e_c_t___i_n_f_o structure:
+
+ typedef int (*getarg_collect_func)(int short_opt,
+ int argc,
+ char **argv,
+ int *optind,
+ int *optarg,
+ void *data);
+
+ typedef struct getarg_collect_info {
+ getarg_collect_func func;
+ void *data;
+ } getarg_collect_info;
+
+ With the _f_u_n_c member set to a function to call, and
+ _d_a_t_a to some application specific data. The parameters
+ to the collect function are:
+
+ _s_h_o_r_t___f_l_a_g non-zero if this call is via a short option
+ flag, zero otherwise
+
+ _a_r_g_c, _a_r_g_v the whole argument list
+
+ _o_p_t_i_n_d pointer to the index in argv where the flag is
+
+ _o_p_t_a_r_g pointer to the index in argv[*optind] where the
+ flag name starts
+
+ _d_a_t_a application specific data
+
+ You can modify _*_o_p_t_i_n_d, and _*_o_p_t_a_r_g, but to do this
+ correct you (more or less) have to know about the in­
+ ner workings of getarg.
+
+ You can skip parts of arguments by increasing _*_o_p_t_a_r_g
+ (you could implement the --zz_3 set of flags from ggzziipp
+ with this), or whole argument strings by increasing
+ _*_o_p_t_i_n_d (let's say you want a flag --cc _x _y _z to specify
+ a coordinate); if you also have to set _*_o_p_t_a_r_g to a
+ sane value.
+
+ The collect function should return one of
+ ARG_ERR_NO_MATCH, ARG_ERR_BAD_ARG, ARG_ERR_NO_ARG on
+ error, zero otherwise.
+
+ For your convenience there is a function,
+ ggeettaarrgg__ooppttaarrgg(), that returns the traditional argument
+ string, and you pass it all arguments, sans data, that
+ where given to the collection function.
+
+ Don't use this more this unless you absolutely have
+ to.
+
+ Option parsing is similar to what getopt uses. Short options without ar­
+ guments can be compressed (--xxyyzz is the same as --xx --yy --zz), and short op­
+ tions with arguments take these as either the rest of the argv-string or
+ as the next option (--oo_f_o_o, or --oo _f_o_o).
+
+ Long option names are prefixed with -- (double dash), and the value with
+ a = (equal), ----ffoooo==_b_a_r. Long option flags can either be specified as they
+ are (----hheellpp), or with an (boolean parsable) option (----hheellpp==_y_e_s,
+ ----hheellpp==_t_r_u_e, or similar), or they can also be negated (----nnoo--hheellpp is the
+ same as ----hheellpp==no), and if you're really confused you can do it multiple
+ times (----nnoo--nnoo--hheellpp==_f_a_l_s_e, or even ----nnoo--nnoo--hheellpp==_m_a_y_b_e).
+
+EEXXAAMMPPLLEE
+ #include <stdio.h>
+ #include <string.h>
+ #include <getarg.h>
+
+ char *source = "Ouagadougou";
+ char *destination;
+ int weight;
+ int include_catalog = 1;
+ int help_flag;
+
+ struct getargs args[] = {
+ { "source", 's', arg_string, &source,
+ "source of shippment", "city" },
+ { "destination", 'd', arg_string, &destination,
+ "destination of shippment", "city" },
+ { "weight", 'w', arg_integer, &weight,
+ "weight of shippment", "tons" },
+ { "catalog", 'c', arg_negative_flag, &include_catalog,
+ "include product catalog" },
+ { "help", 'h', arg_flag, &help_flag }
+ };
+
+ int num_args = sizeof(args) / sizeof(args[0]); /* number of elements in args */
+
+ const char *progname = "ship++";
+
+ int
+ main(int argc, char **argv)
+ {
+ int optind = 0;
+ if (getarg(args, num_args, argc, argv, &optind)) {
+ arg_printusage(args, num_args, progname, "stuff...");
+ exit (1);
+ }
+ if (help_flag) {
+ arg_printusage(args, num_args, progname, "stuff...");
+ exit (0);
+ }
+ if (destination == NULL) {
+ fprintf(stderr, "%s: must specify destination0, progname);
+ exit(1);
+ }
+ if (strcmp(source, destination) == 0) {
+ fprintf(stderr, "%s: destination must be different from source0);
+ exit(1);
+ }
+ /* include more stuff here ... */
+ exit(2);
+ }
+
+ The output help output from this program looks like this:
+
+ $ ship++ --help
+ Usage: ship++ [--source=city] [-s city] [--destination=city] [-d city]
+ [--weight=tons] [-w tons] [--no-catalog] [-c] [--help] [-h] stuff...
+ -s city, --source=city source of shippment
+ -d city, --destination=city destination of shippment
+ -w tons, --weight=tons weight of shippment
+ -c, --no-catalog include product catalog
+
+
+BBUUGGSS
+ It should be more flexible, so it would be possible to use other more
+ complicated option syntaxes, such as what ps(1), and tar(1), uses, or the
+ AFS model where you can skip the flag names as long as the options come
+ in the correct order.
+
+ Options with multiple arguments should be handled better.
+
+ Should be integreated with SL.
+
+ It's very confusing that the struct you pass in is called getargS.
+
+SSEEEE AALLSSOO
+ getopt(3)
+
+ ROKEN September 24, 1999 4
diff --git a/storage/ndb/src/common/util/md5_hash.cpp b/storage/ndb/src/common/util/md5_hash.cpp
new file mode 100644
index 00000000000..d4eedbc40fb
--- /dev/null
+++ b/storage/ndb/src/common/util/md5_hash.cpp
@@ -0,0 +1,239 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+
+#include "md5_hash.hpp"
+
+#ifdef WORDS_BIGENDIAN
+#define HIGHFIRST 1
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * The code has been modified by Mikael Ronstroem to handle
+ * calculating a hash value of a key that is always a multiple
+ * of 4 bytes long. Word 0 of the calculated 4-word hash value
+ * is returned as the hash value.
+ */
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ Uint32 t;
+ do {
+ t = (Uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(Uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(Uint32 buf[4], Uint32 const in[16])
+{
+ register Uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void md5_hash(Uint32 result[4], const Uint64* keybuf, Uint32 no_of_32_words)
+{
+ /**
+ * This is the external interface of the module
+ * It is assumed that keybuf is placed on 8 byte
+ * alignment.
+ */
+ Uint32 i;
+ Uint32 buf[4];
+ Uint64 transform64_buf[8];
+ Uint32* transform32_buf;
+ Uint32 len = no_of_32_words << 2;
+ const Uint64* key64buf = (const Uint64*)keybuf;
+ const Uint32* key32buf = (const Uint32*)keybuf;
+
+ transform32_buf = (Uint32*)&transform64_buf[0];
+ buf[0] = 0x67452301;
+ buf[1] = 0xefcdab89;
+ buf[2] = 0x98badcfe;
+ buf[3] = 0x10325476;
+
+ while (no_of_32_words >= 16) {
+ transform64_buf[0] = key64buf[0];
+ transform64_buf[1] = key64buf[1];
+ transform64_buf[2] = key64buf[2];
+ transform64_buf[3] = key64buf[3];
+ transform64_buf[4] = key64buf[4];
+ transform64_buf[5] = key64buf[5];
+ transform64_buf[6] = key64buf[6];
+ transform64_buf[7] = key64buf[7];
+ no_of_32_words -= 16;
+ key64buf += 8;
+ byteReverse((unsigned char *)transform32_buf, 16);
+ MD5Transform(buf, transform32_buf);
+ }
+
+ key32buf = (const Uint32*)key64buf;
+ transform64_buf[0] = 0;
+ transform64_buf[1] = 0;
+ transform64_buf[2] = 0;
+ transform64_buf[3] = 0;
+ transform64_buf[4] = 0;
+ transform64_buf[5] = 0;
+ transform64_buf[6] = 0;
+ transform64_buf[7] = (Uint64)len;
+
+ for (i = 0; i < no_of_32_words; i++)
+ transform32_buf[i] = key32buf[i];
+ transform32_buf[no_of_32_words] = 0x80000000;
+
+ if (no_of_32_words < 14) {
+ byteReverse((unsigned char *)transform32_buf, 16);
+ MD5Transform(buf, transform32_buf);
+ } else {
+ if (no_of_32_words == 14)
+ transform32_buf[15] = 0;
+ MD5Transform(buf, transform32_buf);
+ transform64_buf[0] = 0;
+ transform64_buf[1] = 0;
+ transform64_buf[2] = 0;
+ transform64_buf[3] = 0;
+ transform64_buf[4] = 0;
+ transform64_buf[5] = 0;
+ transform64_buf[6] = 0;
+ transform64_buf[7] = (Uint64)len;
+ byteReverse((unsigned char *)transform32_buf, 16);
+ MD5Transform(buf, transform32_buf);
+ }
+
+ result[0] = buf[0];
+ result[1] = buf[1];
+ result[2] = buf[2];
+ result[3] = buf[3];
+}
+
diff --git a/storage/ndb/src/common/util/ndb_init.c b/storage/ndb/src/common/util/ndb_init.c
new file mode 100644
index 00000000000..f3aa734d7f9
--- /dev/null
+++ b/storage/ndb/src/common/util/ndb_init.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <my_sys.h>
+
+int
+ndb_init()
+{
+ if (my_init()) {
+ const char* err = "my_init() failed - exit\n";
+ write(2, err, strlen(err));
+ exit(1);
+ }
+ return 0;
+}
+
+void
+ndb_end(int flags)
+{
+ my_end(flags);
+}
diff --git a/storage/ndb/src/common/util/new.cpp b/storage/ndb/src/common/util/new.cpp
new file mode 100644
index 00000000000..901f74bf979
--- /dev/null
+++ b/storage/ndb/src/common/util/new.cpp
@@ -0,0 +1,43 @@
+
+#include <ndb_global.h>
+#include <NdbMem.h>
+
+extern "C" {
+ void (* ndb_new_handler)() = 0;
+}
+
+#ifdef USE_MYSYS_NEW
+
+void *operator new (size_t sz)
+{
+ void * p = NdbMem_Allocate(sz ? sz : 1);
+ if(p)
+ return p;
+ if(ndb_new_handler)
+ (* ndb_new_handler)();
+ abort();
+}
+
+void *operator new[] (size_t sz)
+{
+ void * p = (void *) NdbMem_Allocate(sz ? sz : 1);
+ if(p)
+ return p;
+ if(ndb_new_handler)
+ (* ndb_new_handler)();
+ abort();
+}
+
+void operator delete (void *ptr)
+{
+ if (ptr)
+ NdbMem_Free(ptr);
+}
+
+void operator delete[] (void *ptr) throw ()
+{
+ if (ptr)
+ NdbMem_Free(ptr);
+}
+
+#endif // USE_MYSYS_NEW
diff --git a/storage/ndb/src/common/util/random.c b/storage/ndb/src/common/util/random.c
new file mode 100644
index 00000000000..21235763793
--- /dev/null
+++ b/storage/ndb/src/common/util/random.c
@@ -0,0 +1,284 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/***************************************************************
+* I N C L U D E D F I L E S *
+***************************************************************/
+
+#include <ndb_global.h>
+
+#include <NdbOut.hpp>
+
+#include <random.h>
+
+/***************************************************************
+* L O C A L C O N S T A N T S *
+***************************************************************/
+
+/***************************************************************
+* L O C A L D A T A S T R U C T U R E S *
+***************************************************************/
+
+typedef struct {
+ unsigned short int x[3]; /* Current state. */
+ unsigned short int a[3]; /* Factor in congruential formula. */
+ unsigned short int c; /* Additive const. in congruential formula. */
+ int init; /* Flag for initializing. */
+}DRand48Data;
+
+/***************************************************************
+* L O C A L F U N C T I O N S *
+***************************************************************/
+
+static void shuffleSequence(RandomSequence *seq);
+
+/***************************************************************
+* L O C A L D A T A *
+***************************************************************/
+
+static DRand48Data dRand48Data;
+
+/***************************************************************
+* P U B L I C D A T A *
+***************************************************************/
+
+
+/***************************************************************
+****************************************************************
+* L O C A L F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+static void localRandom48Init(long int seedval, DRand48Data *buffer)
+{
+ /* The standards say we only have 32 bits. */
+ if (sizeof (long int) > 4)
+ seedval &= 0xffffffffl;
+
+#if USHRT_MAX == 0xffffU
+ buffer->x[2] = seedval >> 16;
+ buffer->x[1] = seedval & 0xffffl;
+ buffer->x[0] = 0x330e;
+
+ buffer->a[2] = 0x5;
+ buffer->a[1] = 0xdeec;
+ buffer->a[0] = 0xe66d;
+#else
+ buffer->x[2] = seedval;
+ buffer->x[1] = 0x330e0000UL;
+ buffer->x[0] = 0;
+
+ buffer->a[2] = 0x5deecUL;
+ buffer->a[1] = 0xe66d0000UL;
+ buffer->a[0] = 0;
+#endif
+
+ buffer->c = 0xb;
+ buffer->init = 1;
+}
+
+static void localRandom48(DRand48Data *buffer, long int *result)
+{
+ Uint64 X;
+ Uint64 a;
+ Uint64 loc_result;
+
+ /*--------------------------------------*/
+ /* Initialize buffer, if not yet done. */
+ /*--------------------------------------*/
+ if (!buffer->init) {
+#if (USHRT_MAX == 0xffffU)
+ buffer->a[2] = 0x5;
+ buffer->a[1] = 0xdeec;
+ buffer->a[0] = 0xe66d;
+#else
+ buffer->a[2] = 0x5deecUL;
+ buffer->a[1] = 0xe66d0000UL;
+ buffer->a[0] = 0;
+#endif
+ buffer->c = 0xb;
+ buffer->init = 1;
+ }
+
+ /* Do the real work. We choose a data type which contains at least
+ 48 bits. Because we compute the modulus it does not care how
+ many bits really are computed. */
+
+ if (sizeof (unsigned short int) == 2) {
+ X = (Uint64)buffer->x[2] << 32 |
+ (Uint64)buffer->x[1] << 16 |
+ buffer->x[0];
+ a = ((Uint64)buffer->a[2] << 32 |
+ (Uint64)buffer->a[1] << 16 |
+ buffer->a[0]);
+
+ loc_result = X * a + buffer->c;
+
+ buffer->x[0] = loc_result & 0xffff;
+ buffer->x[1] = (loc_result >> 16) & 0xffff;
+ buffer->x[2] = (loc_result >> 32) & 0xffff;
+ }
+ else {
+ X = (Uint64)buffer->x[2] << 16 |
+ buffer->x[1] >> 16;
+ a = (Uint64)buffer->a[2] << 16 |
+ buffer->a[1] >> 16;
+
+ loc_result = X * a + buffer->c;
+
+ buffer->x[0] = loc_result >> 16 & 0xffffffffl;
+ buffer->x[1] = loc_result << 16 & 0xffff0000l;
+ }
+
+ /*--------------------*/
+ /* Store the result. */
+ /*--------------------*/
+ if (sizeof (unsigned short int) == 2)
+ *result = buffer->x[2] << 15 | buffer->x[1] >> 1;
+ else
+ *result = buffer->x[2] >> 1;
+}
+
+static void shuffleSequence(RandomSequence *seq)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int tmp;
+
+ if( !seq ) return;
+
+ for(i = 0; i < seq->length; i++ ) {
+ j = myRandom48(seq->length);
+ if( i != j ) {
+ tmp = seq->values[i];
+ seq->values[i] = seq->values[j];
+ seq->values[j] = tmp;
+ }
+ }
+}
+
+
+/***************************************************************
+****************************************************************
+* P U B L I C F U N C T I O N S C O D E S E C T I O N *
+****************************************************************
+***************************************************************/
+
+
+double getTps(unsigned int count, double timeValue)
+{
+ double f;
+
+ if( timeValue != 0.0 )
+ f = count / timeValue;
+ else
+ f = 0.0;
+
+ return(f);
+}
+
+/*----------------------------*/
+/* Random Sequences Functions */
+/*----------------------------*/
+int initSequence(RandomSequence *seq, SequenceValues *inputValues)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int totalLength;
+ unsigned int index;
+
+ if( !seq || !inputValues ) return(-1);
+
+ /*------------------------------------*/
+ /* Find the total length of the array */
+ /*------------------------------------*/
+ totalLength = 0;
+
+ for(i = 0; inputValues[i].length != 0; i++)
+ totalLength += inputValues[i].length;
+
+ if( totalLength == 0 ) return(-1);
+
+ seq->length = totalLength;
+ seq->values = calloc(totalLength, sizeof(unsigned int));
+
+ if( seq->values == 0 ) return(-1);
+
+ /*----------------------*/
+ /* set the array values */
+ /*----------------------*/
+ index = 0;
+
+ for(i = 0; inputValues[i].length != 0; i++) {
+ for(j = 0; j < inputValues[i].length; j++ ) {
+ seq->values[index] = inputValues[i].value;
+ index++;
+ }
+ }
+
+ shuffleSequence(seq);
+
+ seq->currentIndex = 0;
+
+ return(0);
+}
+
+unsigned int getNextRandom(RandomSequence *seq)
+{
+ unsigned int nextValue;
+
+ nextValue = seq->values[seq->currentIndex];
+
+ seq->currentIndex++;
+
+ if(seq->currentIndex == seq->length){
+ seq->currentIndex = 0;
+ shuffleSequence(seq);
+ }
+
+ return nextValue;
+}
+
+void printSequence(RandomSequence *seq, unsigned int numPerRow)
+{
+ unsigned int i;
+
+ if( !seq ) return;
+
+ for(i = 0; i<seq->length; i++) {
+ ndbout_c("%d ", seq->values[i]);
+
+ if((i+1) % numPerRow == 0)
+ ndbout_c("");
+ }
+
+ if(i % numPerRow != 0)
+ ndbout_c("");
+}
+
+void myRandom48Init(long int seedval)
+{
+ localRandom48Init(seedval, &dRand48Data);
+}
+
+long int myRandom48(unsigned int maxValue)
+{
+ long int result;
+
+ localRandom48(&dRand48Data, &result);
+
+ return(result % maxValue);
+}
diff --git a/storage/ndb/src/common/util/socket_io.cpp b/storage/ndb/src/common/util/socket_io.cpp
new file mode 100644
index 00000000000..83a546de773
--- /dev/null
+++ b/storage/ndb/src/common/util/socket_io.cpp
@@ -0,0 +1,281 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+
+#include <NdbTCP.h>
+#include <socket_io.h>
+#include <NdbOut.hpp>
+
+extern "C"
+int
+read_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ char * buf, int buflen){
+ if(buflen < 1)
+ return 0;
+
+ fd_set readset;
+ FD_ZERO(&readset);
+ FD_SET(socket, &readset);
+
+ struct timeval timeout;
+ timeout.tv_sec = (timeout_millis / 1000);
+ timeout.tv_usec = (timeout_millis % 1000) * 1000;
+
+ const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
+ if(selectRes == 0)
+ return 0;
+
+ if(selectRes == -1){
+ return -1;
+ }
+
+ return recv(socket, &buf[0], buflen, 0);
+}
+
+extern "C"
+int
+readln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ char * buf, int buflen){
+ if(buflen <= 1)
+ return 0;
+
+ fd_set readset;
+ FD_ZERO(&readset);
+ FD_SET(socket, &readset);
+
+ struct timeval timeout;
+ timeout.tv_sec = (timeout_millis / 1000);
+ timeout.tv_usec = (timeout_millis % 1000) * 1000;
+
+ const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
+ if(selectRes == 0)
+ return 0;
+
+ if(selectRes == -1){
+ return -1;
+ }
+
+ int pos = 0; buf[pos] = 0;
+ while(true){
+ const int t = recv(socket, &buf[pos], 1, 0);
+ if(t != 1){
+ return -1;
+ }
+ if(buf[pos] == '\n'){
+ buf[pos] = 0;
+
+ if(pos > 0 && buf[pos-1] == '\r'){
+ pos--;
+ buf[pos] = 0;
+ }
+
+ return pos;
+ }
+ pos++;
+ if(pos == (buflen - 1)){
+ buf[pos] = 0;
+ return buflen;
+ }
+
+ FD_ZERO(&readset);
+ FD_SET(socket, &readset);
+ timeout.tv_sec = (timeout_millis / 1000);
+ timeout.tv_usec = (timeout_millis % 1000) * 1000;
+ const int selectRes = select(socket + 1, &readset, 0, 0, &timeout);
+ if(selectRes != 1){
+ return -1;
+ }
+ }
+}
+
+extern "C"
+int
+write_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ const char buf[], int len){
+ fd_set writeset;
+ FD_ZERO(&writeset);
+ FD_SET(socket, &writeset);
+ struct timeval timeout;
+ timeout.tv_sec = (timeout_millis / 1000);
+ timeout.tv_usec = (timeout_millis % 1000) * 1000;
+
+ const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout);
+ if(selectRes != 1){
+ return -1;
+ }
+
+ const char * tmp = &buf[0];
+ while(len > 0){
+ const int w = send(socket, tmp, len, 0);
+ if(w == -1){
+ return -1;
+ }
+ len -= w;
+ tmp += w;
+
+ if(len == 0)
+ break;
+
+ FD_ZERO(&writeset);
+ FD_SET(socket, &writeset);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ const int selectRes = select(socket + 1, 0, &writeset, 0, &timeout);
+ if(selectRes != 1){
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+extern "C"
+int
+print_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ const char * fmt, ...){
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = vprint_socket(socket, timeout_millis, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+extern "C"
+int
+println_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ const char * fmt, ...){
+ va_list ap;
+ va_start(ap, fmt);
+ int ret = vprintln_socket(socket, timeout_millis, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+extern "C"
+int
+vprint_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ const char * fmt, va_list ap){
+ char buf[1000];
+ char *buf2 = buf;
+ size_t size;
+
+ if (fmt != 0 && fmt[0] != 0) {
+ size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap);
+ /* Check if the output was truncated */
+ if(size > sizeof(buf)) {
+ buf2 = (char *)malloc(size);
+ if(buf2 == NULL)
+ return -1;
+ BaseString::vsnprintf(buf2, size, fmt, ap);
+ }
+ } else
+ return 0;
+
+ int ret = write_socket(socket, timeout_millis, buf2, size);
+ if(buf2 != buf)
+ free(buf2);
+ return ret;
+}
+
+extern "C"
+int
+vprintln_socket(NDB_SOCKET_TYPE socket, int timeout_millis,
+ const char * fmt, va_list ap){
+ char buf[1000];
+ char *buf2 = buf;
+ size_t size;
+
+ if (fmt != 0 && fmt[0] != 0) {
+ size = BaseString::vsnprintf(buf, sizeof(buf), fmt, ap)+1;// extra byte for '/n'
+ /* Check if the output was truncated */
+ if(size > sizeof(buf)) {
+ buf2 = (char *)malloc(size);
+ if(buf2 == NULL)
+ return -1;
+ BaseString::vsnprintf(buf2, size, fmt, ap);
+ }
+ } else {
+ size = 1;
+ }
+ buf2[size-1]='\n';
+
+ int ret = write_socket(socket, timeout_millis, buf2, size);
+ if(buf2 != buf)
+ free(buf2);
+ return ret;
+}
+
+#ifdef NDB_WIN32
+
+class INIT_WINSOCK2
+{
+public:
+ INIT_WINSOCK2(void);
+ ~INIT_WINSOCK2(void);
+
+private:
+ bool m_bAcceptable;
+};
+
+INIT_WINSOCK2 g_init_winsock2;
+
+INIT_WINSOCK2::INIT_WINSOCK2(void)
+: m_bAcceptable(false)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+
+ wVersionRequested = MAKEWORD( 2, 2 );
+
+ err = WSAStartup( wVersionRequested, &wsaData );
+ if ( err != 0 ) {
+ /* Tell the user that we could not find a usable */
+ /* WinSock DLL. */
+ m_bAcceptable = false;
+ }
+
+ /* Confirm that the WinSock DLL supports 2.2.*/
+ /* Note that if the DLL supports versions greater */
+ /* than 2.2 in addition to 2.2, it will still return */
+ /* 2.2 in wVersion since that is the version we */
+ /* requested. */
+
+ if ( LOBYTE( wsaData.wVersion ) != 2 ||
+ HIBYTE( wsaData.wVersion ) != 2 ) {
+ /* Tell the user that we could not find a usable */
+ /* WinSock DLL. */
+ WSACleanup( );
+ m_bAcceptable = false;
+ }
+
+ /* The WinSock DLL is acceptable. Proceed. */
+ m_bAcceptable = true;
+}
+
+INIT_WINSOCK2::~INIT_WINSOCK2(void)
+{
+ if(m_bAcceptable)
+ {
+ m_bAcceptable = false;
+ WSACleanup();
+ }
+}
+
+#endif
+
diff --git a/storage/ndb/src/common/util/strdup.c b/storage/ndb/src/common/util/strdup.c
new file mode 100644
index 00000000000..d8f4d99bd28
--- /dev/null
+++ b/storage/ndb/src/common/util/strdup.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+
+#ifndef HAVE_STRDUP
+char *
+strdup(const char *s){
+ void *p2;
+ if ((p2 = malloc(strlen(s)+1)))
+ strcpy(p2, s);
+ return p2;
+}
+#endif
diff --git a/storage/ndb/src/common/util/testConfigValues/Makefile b/storage/ndb/src/common/util/testConfigValues/Makefile
new file mode 100644
index 00000000000..5b7400f5ee3
--- /dev/null
+++ b/storage/ndb/src/common/util/testConfigValues/Makefile
@@ -0,0 +1,12 @@
+include .defs.mk
+
+TYPE := util
+
+BIN_TARGET := testConfigValues
+BIN_TARGET_ARCHIVES := portlib general
+
+SOURCES := testConfigValues.cpp
+
+CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/util)
+
+include $(NDB_TOP)/Epilogue.mk
diff --git a/storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp b/storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp
new file mode 100644
index 00000000000..362deb1ddad
--- /dev/null
+++ b/storage/ndb/src/common/util/testConfigValues/testConfigValues.cpp
@@ -0,0 +1,122 @@
+#include <ConfigValues.hpp>
+#include <NdbOut.hpp>
+#include <stdlib.h>
+#include <string.h>
+
+#define CF_NODES 1
+#define CF_LOG_PAGES 2
+#define CF_MEM_PAGES 3
+#define CF_START_TO 4
+#define CF_STOP_TO 5
+
+void print(Uint32 i, ConfigValues::ConstIterator & cf){
+ ndbout_c("---");
+ for(Uint32 j = 2; j<=7; j++){
+ switch(cf.getTypeOf(j)){
+ case ConfigValues::IntType:
+ ndbout_c("Node %d : CFG(%d) : %d",
+ i, j, cf.get(j, 999));
+ break;
+ case ConfigValues::Int64Type:
+ ndbout_c("Node %d : CFG(%d) : %lld (64)",
+ i, j, cf.get64(j, 999));
+ break;
+ case ConfigValues::StringType:
+ ndbout_c("Node %d : CFG(%d) : %s",
+ i, j, cf.get(j, "<NOT FOUND>"));
+ break;
+ default:
+ ndbout_c("Node %d : CFG(%d) : TYPE: %d",
+ i, j, cf.getTypeOf(j));
+ }
+ }
+}
+
+void print(Uint32 i, ConfigValues & _cf){
+ ConfigValues::ConstIterator cf(_cf);
+ print(i, cf);
+}
+
+void
+print(ConfigValues & _cf){
+ ConfigValues::ConstIterator cf(_cf);
+ Uint32 i = 0;
+ while(cf.openSection(CF_NODES, i)){
+ print(i, cf);
+ cf.closeSection();
+ i++;
+ }
+}
+
+inline
+void
+require(bool b){
+ if(!b)
+ abort();
+}
+
+int
+main(void){
+
+ {
+ ConfigValuesFactory cvf(10, 20);
+ cvf.openSection(1, 0);
+ cvf.put(2, 12);
+ cvf.put64(3, 13);
+ cvf.put(4, 14);
+ cvf.put64(5, 15);
+ cvf.put(6, "Keso");
+ cvf.put(7, "Kent");
+ cvf.closeSection();
+
+ cvf.openSection(1, 1);
+ cvf.put(2, 22);
+ cvf.put64(3, 23);
+ cvf.put(4, 24);
+ cvf.put64(5, 25);
+ cvf.put(6, "Kalle");
+ cvf.put(7, "Anka");
+ cvf.closeSection();
+
+ ndbout_c("-- print --");
+ print(* cvf.m_cfg);
+
+ cvf.shrink();
+ ndbout_c("shrink\n-- print --");
+ print(* cvf.m_cfg);
+ cvf.expand(10, 10);
+ ndbout_c("expand\n-- print --");
+ print(* cvf.m_cfg);
+
+ ndbout_c("packed size: %d", cvf.m_cfg->getPackedSize());
+
+ ConfigValues::ConstIterator iter(* cvf.m_cfg);
+ iter.openSection(CF_NODES, 0);
+ ConfigValues * cfg2 = ConfigValuesFactory::extractCurrentSection(iter);
+ print(99, * cfg2);
+
+ cvf.shrink();
+ ndbout_c("packed size: %d", cfg2->getPackedSize());
+
+ UtilBuffer buf;
+ Uint32 l1 = cvf.m_cfg->pack(buf);
+ Uint32 l2 = cvf.m_cfg->getPackedSize();
+ require(l1 == l2);
+
+ ConfigValuesFactory cvf2;
+ require(cvf2.unpack(buf));
+ UtilBuffer buf2;
+ cvf2.shrink();
+ Uint32 l3 = cvf2.m_cfg->pack(buf2);
+ require(l1 == l3);
+
+ ndbout_c("unpack\n-- print --");
+ print(* cvf2.m_cfg);
+
+ cfg2->~ConfigValues();;
+ cvf.m_cfg->~ConfigValues();
+ free(cfg2);
+ free(cvf.m_cfg);
+ }
+ return 0;
+}
diff --git a/storage/ndb/src/common/util/testProperties/Makefile b/storage/ndb/src/common/util/testProperties/Makefile
new file mode 100644
index 00000000000..343c07a49e7
--- /dev/null
+++ b/storage/ndb/src/common/util/testProperties/Makefile
@@ -0,0 +1,9 @@
+include .defs.mk
+
+TYPE := util
+
+BIN_TARGET := keso
+
+SOURCES := testProperties.cpp
+
+include $(NDB_TOP)/Epilogue.mk
diff --git a/storage/ndb/src/common/util/testProperties/testProperties.cpp b/storage/ndb/src/common/util/testProperties/testProperties.cpp
new file mode 100644
index 00000000000..e445f7ca3e4
--- /dev/null
+++ b/storage/ndb/src/common/util/testProperties/testProperties.cpp
@@ -0,0 +1,195 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include "Properties.hpp"
+#include <NdbOut.hpp>
+
+#include "uucode.h"
+
+bool
+writeToFile(const Properties & p, const char * fname, bool uu = true){
+ Uint32 sz = p.getPackedSize();
+ char * buffer = (char*)malloc(sz);
+
+ FILE * f = fopen(fname, "wb");
+ bool res = p.pack((Uint32*)buffer);
+ if(res != true){
+ ndbout << "Error packing" << endl;
+ ndbout << "p.getPropertiesErrno() = " << p.getPropertiesErrno() << endl;
+ ndbout << "p.getOSErrno() = " << p.getOSErrno() << endl;
+ }
+ if(uu)
+ uuencode(buffer, sz, f);
+ else {
+ fwrite(buffer, 1, sz, f);
+ }
+
+ fclose(f);
+ free(buffer);
+ return res;
+}
+
+bool
+readFromFile(Properties & p, const char *fname, bool uu = true){
+ Uint32 sz = 30000;
+ char * buffer = (char*)malloc(sz);
+ FILE * f = fopen(fname, "rb");
+ if(uu)
+ uudecode(f, buffer, sz);
+ else
+ fread(buffer, 1, sz, f);
+ fclose(f);
+ bool res = p.unpack((Uint32*)buffer, sz);
+ if(res != true){
+ ndbout << "Error unpacking" << endl;
+ ndbout << "p.getPropertiesErrno() = " << p.getPropertiesErrno() << endl;
+ ndbout << "p.getOSErrno() = " << p.getOSErrno() << endl;
+ }
+ free(buffer);
+ return res;
+}
+
+void putALot(Properties & tmp){
+ int i = 123;
+ tmp.put("LockPagesInMainMemory", i++);
+ tmp.put("SleepWhenIdle", i++);
+ tmp.put("NoOfSignalsToExecuteBetweenCommunicationInterfacePoll", i++);
+ tmp.put("TimeBetweenWatchDogCheck", i++);
+ tmp.put("StopOnError", i++);
+
+ tmp.put("MaxNoOfConcurrentOperations", i++);
+ tmp.put("MaxNoOfConcurrentTransactions", i++);
+ tmp.put("MemorySpaceIndexes", i++);
+ tmp.put("MemorySpaceTuples", i++);
+ tmp.put("MemoryDiskPages", i++);
+ tmp.put("NoOfFreeDiskClusters", i++);
+ tmp.put("NoOfDiskClusters", i++);
+
+ tmp.put("TimeToWaitAlive", i++);
+ tmp.put("HeartbeatIntervalDbDb", i++);
+ tmp.put("HeartbeatIntervalDbApi", i++);
+ tmp.put("TimeBetweenInactiveTransactionAbortCheck", i++);
+
+ tmp.put("TimeBetweenLocalCheckpoints", i++);
+ tmp.put("TimeBetweenGlobalCheckpoints", i++);
+ tmp.put("NoOfFragmentLogFiles", i++);
+ tmp.put("NoOfConcurrentCheckpointsDuringRestart", i++);
+ tmp.put("TransactionInactiveTimeBeforeAbort", i++);
+ tmp.put("NoOfConcurrentProcessesHandleTakeover", i++);
+
+ tmp.put("NoOfConcurrentCheckpointsAfterRestart", i++);
+
+ tmp.put("NoOfDiskPagesToDiskDuringRestartTUP", i++);
+ tmp.put("NoOfDiskPagesToDiskAfterRestartTUP", i++);
+ tmp.put("NoOfDiskPagesToDiskDuringRestartACC", i++);
+ tmp.put("NoOfDiskPagesToDiskAfterRestartACC", i++);
+
+ tmp.put("NoOfDiskClustersPerDiskFile", i++);
+ tmp.put("NoOfDiskFiles", i++);
+
+ // Always found
+ tmp.put("NoOfReplicas", 33);
+ tmp.put("MaxNoOfAttributes", 34);
+ tmp.put("MaxNoOfTables", 35);
+}
+
+int
+main(void){
+ Properties p;
+
+ p.put("Kalle", 1);
+ p.put("Ank1", "anka");
+ p.put("Ank2", "anka");
+ p.put("Ank3", "anka");
+ p.put("Ank4", "anka");
+ putALot(p);
+
+ Properties tmp;
+ tmp.put("Type", "TCP");
+ tmp.put("OwnNodeId", 1);
+ tmp.put("RemoteNodeId", 2);
+ tmp.put("OwnHostName", "local");
+ tmp.put("RemoteHostName", "remote");
+
+ tmp.put("SendSignalId", 1);
+ tmp.put("Compression", (Uint32)false);
+ tmp.put("Checksum", 1);
+
+ tmp.put64("SendBufferSize", 2000);
+ tmp.put64("MaxReceiveSize", 1000);
+
+ tmp.put("PortNumber", 1233);
+ putALot(tmp);
+
+ p.put("Connection", 1, &tmp);
+
+ p.put("NoOfConnections", 2);
+ p.put("NoOfConnection2", 2);
+
+ p.put("kalle", 3);
+ p.put("anka", "kalle");
+
+ Properties p2;
+ p2.put("kalle", "anka");
+
+ p.put("prop", &p2);
+
+ p.put("Connection", 2, &tmp);
+
+ p.put("Connection", 3, &tmp);
+
+ p.put("Connection", 4, &tmp);
+ /*
+ */
+
+ Uint32 a = 99;
+ const char * b;
+ const Properties * p3;
+ Properties * p4;
+
+ bool bb = p.get("kalle", &a);
+ bool cc = p.get("anka", &b);
+ bool dd = p.get("prop", &p3);
+ if(p.getCopy("prop", &p4))
+ delete p4;
+
+ p2.put("p2", &p2);
+
+ p.put("prop2", &p2);
+ /* */
+
+ p.print(stdout, "testing 1: ");
+
+ writeToFile(p, "A_1");
+ writeToFile(p, "B_1", false);
+
+ Properties r1;
+ readFromFile(r1, "A_1");
+ writeToFile(r1, "A_3");
+
+ //r1.print(stdout, "testing 2: ");
+ Properties r2;
+ readFromFile(r2, "A_1");
+ writeToFile(r2, "A_4");
+
+ Properties r3;
+ readFromFile(r3, "B_1", false);
+ writeToFile(r3, "A_5");
+ r3.print(stdout, "testing 3: ");
+
+ return 0;
+}
diff --git a/storage/ndb/src/common/util/testSimpleProperties/Makefile b/storage/ndb/src/common/util/testSimpleProperties/Makefile
new file mode 100644
index 00000000000..89d33fa8dd8
--- /dev/null
+++ b/storage/ndb/src/common/util/testSimpleProperties/Makefile
@@ -0,0 +1,12 @@
+include .defs.mk
+
+TYPE := util
+
+BIN_TARGET := sp_test
+BIN_TARGET_ARCHIVES := portlib general
+
+SOURCES := sp_test.cpp
+
+CCFLAGS_LOC += -I$(call fixpath,$(NDB_TOP)/include/util)
+
+include $(NDB_TOP)/Epilogue.mk
diff --git a/storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp b/storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp
new file mode 100644
index 00000000000..d4052b64132
--- /dev/null
+++ b/storage/ndb/src/common/util/testSimpleProperties/sp_test.cpp
@@ -0,0 +1,95 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+
+#include "SimpleProperties.hpp"
+#include <NdbOut.hpp>
+
+Uint32 page[8192];
+
+int writer();
+int reader(Uint32 *, Uint32 len);
+int unpack(Uint32 *, Uint32 len);
+
+int main(){
+ int len = writer();
+ reader(page, len);
+ unpack(page, len);
+
+ return 0;
+}
+
+int
+writer(){
+ LinearWriter w(&page[0], 8192);
+
+ w.first();
+ w.add(1, 2);
+ w.add(7, 3);
+ w.add(3, "jonas");
+ w.add(5, "0123456789");
+ w.add(7, 4);
+ w.add(3, "e cool");
+ w.add(5, "9876543210");
+
+ ndbout_c("WordsUsed = %d", w.getWordsUsed());
+
+ return w.getWordsUsed();
+}
+
+int
+reader(Uint32 * pages, Uint32 len){
+ SimplePropertiesLinearReader it(pages, len);
+
+ it.printAll(ndbout);
+ return 0;
+}
+
+struct Test {
+ Uint32 val1;
+ Uint32 val7;
+ char val3[100];
+ Test() : val1(0xFFFFFFFF), val7(0xFFFFFFFF) { sprintf(val3, "bad");}
+};
+
+static const
+SimpleProperties::SP2StructMapping
+test_map [] = {
+ { 1, offsetof(Test, val1), SimpleProperties::Uint32Value, 0, ~0 },
+ { 7, offsetof(Test, val7), SimpleProperties::Uint32Value, 0, ~0 },
+ { 3, offsetof(Test, val3), SimpleProperties::StringValue, 0, sizeof(100) },
+ { 5, 0, SimpleProperties::InvalidValue, 0, 0 }
+};
+
+static unsigned
+test_map_sz = sizeof(test_map)/sizeof(test_map[0]);
+
+int
+unpack(Uint32 * pages, Uint32 len){
+ Test test;
+ SimplePropertiesLinearReader it(pages, len);
+ SimpleProperties::UnpackStatus status;
+ while((status = SimpleProperties::unpack(it, &test, test_map, test_map_sz,
+ true, false)) == SimpleProperties::Break){
+ ndbout << "test.val1 = " << test.val1 << endl;
+ ndbout << "test.val7 = " << test.val7 << endl;
+ ndbout << "test.val3 = " << test.val3 << endl;
+ it.next();
+ }
+ assert(status == SimpleProperties::Eof);
+ return 0;
+}
diff --git a/storage/ndb/src/common/util/uucode.c b/storage/ndb/src/common/util/uucode.c
new file mode 100644
index 00000000000..da34d565153
--- /dev/null
+++ b/storage/ndb/src/common/util/uucode.c
@@ -0,0 +1,234 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+
+/* ENC is the basic 1 character encoding function to make a char printing */
+/* DEC is single character decode */
+#define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
+#define DEC(c) (((c) - ' ') & 077)
+
+/*
+ * copy from in to out, encoding as you go along.
+ */
+void
+uuencode(const char * data, int dataLen, FILE * out)
+{
+ int ch, n;
+ const char *p = data;
+
+ fprintf(out, "begin\n");
+
+ while (dataLen > 0){
+ n = dataLen > 45 ? 45 : dataLen;
+ dataLen -= n;
+ ch = ENC(n);
+ if (putc(ch, out) == EOF)
+ break;
+ for (; n > 0; n -= 3, p += 3) {
+ char p_0 = * p;
+ char p_1 = 0;
+ char p_2 = 0;
+
+ if(n >= 2){
+ p_1 = p[1];
+ }
+ if(n >= 3){
+ p_2 = p[2];
+ }
+
+ ch = p_0 >> 2;
+ ch = ENC(ch);
+ if (putc(ch, out) == EOF)
+ break;
+ ch = ((p_0 << 4) & 060) | ((p_1 >> 4) & 017);
+ ch = ENC(ch);
+ if (putc(ch, out) == EOF)
+ break;
+ ch = ((p_1 << 2) & 074) | ((p_2 >> 6) & 03);
+ ch = ENC(ch);
+ if (putc(ch, out) == EOF)
+ break;
+ ch = p_2 & 077;
+ ch = ENC(ch);
+ if (putc(ch, out) == EOF)
+ break;
+ }
+ if (putc('\n', out) == EOF)
+ break;
+ }
+ ch = ENC('\0');
+ putc(ch, out);
+ putc('\n', out);
+ fprintf(out, "end\n");
+}
+
+int
+uudecode(FILE * input, char * outBuf, int bufLen){
+ int n;
+ char ch, *p, returnCode;
+ char buf[255];
+
+ returnCode = 0;
+ /* search for header line */
+ do {
+ if (!fgets(buf, sizeof(buf), input)) {
+ return 1;
+ }
+ } while (strncmp(buf, "begin", 5));
+
+ /* for each input line */
+ for (;;) {
+ if (!fgets(p = buf, sizeof(buf), input)) {
+ return 1;
+ }
+ /*
+ * `n' is used to avoid writing out all the characters
+ * at the end of the file.
+ */
+ if ((n = DEC(*p)) <= 0)
+ break;
+ if(n >= bufLen){
+ returnCode = 1;
+ break;
+ }
+ for (++p; n > 0; p += 4, n -= 3)
+ if (n >= 3) {
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ * outBuf = ch; outBuf++; bufLen--;
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ * outBuf = ch; outBuf++; bufLen--;
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ * outBuf = ch; outBuf++; bufLen--;
+ } else {
+ if (n >= 1) {
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ * outBuf = ch; outBuf++; bufLen--;
+ }
+ if (n >= 2) {
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ * outBuf = ch; outBuf++; bufLen--;
+ }
+ if (n >= 3) {
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ * outBuf = ch; outBuf++; bufLen--;
+ }
+ }
+ }
+ if (!fgets(buf, sizeof(buf), input) || strcmp(buf, "end\n")) {
+ return 1;
+ }
+ return returnCode;
+}
+
+int
+uuencode_mem(char * dst, const char * data, int dataLen)
+{
+ int sz = 0;
+
+ int ch, n;
+ const char *p = data;
+
+ while (dataLen > 0){
+ n = dataLen > 45 ? 45 : dataLen;
+ dataLen -= n;
+ ch = ENC(n);
+ * dst = ch; dst++; sz++;
+ for (; n > 0; n -= 3, p += 3) {
+ char p_0 = * p;
+ char p_1 = 0;
+ char p_2 = 0;
+
+ if(n >= 2){
+ p_1 = p[1];
+ }
+ if(n >= 3){
+ p_2 = p[2];
+ }
+
+ ch = p_0 >> 2;
+ ch = ENC(ch);
+ * dst = ch; dst++; sz++;
+
+ ch = ((p_0 << 4) & 060) | ((p_1 >> 4) & 017);
+ ch = ENC(ch);
+ * dst = ch; dst++; sz++;
+
+ ch = ((p_1 << 2) & 074) | ((p_2 >> 6) & 03);
+ ch = ENC(ch);
+ * dst = ch; dst++; sz++;
+
+ ch = p_2 & 077;
+ ch = ENC(ch);
+ * dst = ch; dst++; sz++;
+ }
+
+ * dst = '\n'; dst++; sz++;
+ }
+ ch = ENC('\0');
+ * dst = ch; dst++; sz++;
+
+ * dst = '\n'; dst++; sz++;
+ * dst = 0; dst++; sz++;
+
+ return sz;
+}
+
+int
+uudecode_mem(char * outBuf, int bufLen, const char * src){
+ int n;
+ char ch;
+ int sz = 0;
+ const char * p = src;
+
+ /*
+ * `n' is used to avoid writing out all the characters
+ * at the end of the file.
+ */
+ if ((n = DEC(*p)) <= 0)
+ return 0;
+ if(n >= bufLen){
+ return -1;
+ }
+ for (++p; n > 0; p += 4, n -= 3){
+ if (n >= 3) {
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ * outBuf = ch; outBuf++; bufLen--; sz++;
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ * outBuf = ch; outBuf++; bufLen--; sz++;
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ * outBuf = ch; outBuf++; bufLen--; sz++;
+ } else {
+ if (n >= 1) {
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ * outBuf = ch; outBuf++; bufLen--; sz++;
+ }
+ if (n >= 2) {
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ * outBuf = ch; outBuf++; bufLen--; sz++;
+ }
+ if (n >= 3) {
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ * outBuf = ch; outBuf++; bufLen--; sz++;
+ }
+ }
+ }
+ return sz;
+}
+
+
+
diff --git a/storage/ndb/src/common/util/version.c b/storage/ndb/src/common/util/version.c
new file mode 100644
index 00000000000..dfbb1e4a2e6
--- /dev/null
+++ b/storage/ndb/src/common/util/version.c
@@ -0,0 +1,238 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <ndb_version.h>
+#include <version.h>
+#include <basestring_vsnprintf.h>
+#include <NdbEnv.h>
+#include <NdbOut.hpp>
+
+Uint32 getMajor(Uint32 version) {
+ return (version >> 16) & 0xFF;
+}
+
+Uint32 getMinor(Uint32 version) {
+ return (version >> 8) & 0xFF;
+}
+
+Uint32 getBuild(Uint32 version) {
+ return (version >> 0) & 0xFF;
+}
+
+Uint32 makeVersion(Uint32 major, Uint32 minor, Uint32 build) {
+ return MAKE_VERSION(major, minor, build);
+
+}
+
+const char * getVersionString(Uint32 version, const char * status) {
+ char buff[100];
+ if (status && status[0] != 0)
+ basestring_snprintf(buff, sizeof(buff),
+ "Version %d.%d.%d (%s)",
+ getMajor(version),
+ getMinor(version),
+ getBuild(version),
+ status);
+ else
+ basestring_snprintf(buff, sizeof(buff),
+ "Version %d.%d.%d",
+ getMajor(version),
+ getMinor(version),
+ getBuild(version));
+ return strdup(buff);
+}
+
+typedef enum {
+ UG_Null,
+ UG_Range,
+ UG_Exact
+} UG_MatchType;
+
+struct NdbUpGradeCompatible {
+ Uint32 ownVersion;
+ Uint32 otherVersion;
+ UG_MatchType matchType;
+};
+
+/*#define TEST_VERSION*/
+
+#define HAVE_NDB_SETVERSION
+#ifdef HAVE_NDB_SETVERSION
+Uint32 ndbOwnVersionTesting = 0;
+void
+ndbSetOwnVersion() {
+ char buf[256];
+ if (NdbEnv_GetEnv("NDB_SETVERSION", buf, sizeof(buf))) {
+ Uint32 _v1,_v2,_v3;
+ if (sscanf(buf, "%u.%u.%u", &_v1, &_v2, &_v3) == 3) {
+ ndbOwnVersionTesting = MAKE_VERSION(_v1,_v2,_v3);
+ ndbout_c("Testing: Version set to 0x%x", ndbOwnVersionTesting);
+ }
+ }
+}
+#else
+void ndbSetOwnVersion() {}
+#endif
+
+#ifndef TEST_VERSION
+struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
+ { MAKE_VERSION(5,0,3), MAKE_VERSION(5,0,2), UG_Exact },
+ { MAKE_VERSION(4,1,9), MAKE_VERSION(4,1,8), UG_Exact },
+ { MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact },
+ { 0, 0, UG_Null }
+};
+
+struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = {
+ { MAKE_VERSION(5,0,2), MAKE_VERSION(4,1,8), UG_Exact },
+ { MAKE_VERSION(3,5,4), MAKE_VERSION(3,5,3), UG_Exact },
+ { 0, 0, UG_Null }
+};
+
+#else /* testing purposes */
+
+struct NdbUpGradeCompatible ndbCompatibleTable_full[] = {
+ { MAKE_VERSION(4,1,5), MAKE_VERSION(4,1,0), UG_Range },
+ { MAKE_VERSION(3,6,9), MAKE_VERSION(3,6,1), UG_Range },
+ { MAKE_VERSION(3,6,2), MAKE_VERSION(3,6,1), UG_Range },
+ { MAKE_VERSION(3,5,7), MAKE_VERSION(3,5,0), UG_Range },
+ { MAKE_VERSION(3,5,1), MAKE_VERSION(3,5,0), UG_Range },
+ { NDB_VERSION_D , MAKE_VERSION(NDB_VERSION_MAJOR,NDB_VERSION_MINOR,2), UG_Range },
+ { 0, 0, UG_Null }
+};
+
+struct NdbUpGradeCompatible ndbCompatibleTable_upgrade[] = {
+ { MAKE_VERSION(4,1,5), MAKE_VERSION(3,6,9), UG_Exact },
+ { MAKE_VERSION(3,6,2), MAKE_VERSION(3,5,7), UG_Exact },
+ { MAKE_VERSION(3,5,1), NDB_VERSION_D , UG_Exact },
+ { 0, 0, UG_Null }
+};
+
+
+#endif
+
+void ndbPrintVersion()
+{
+ printf("Version: %u.%u.%u\n",
+ getMajor(ndbGetOwnVersion()),
+ getMinor(ndbGetOwnVersion()),
+ getBuild(ndbGetOwnVersion()));
+}
+
+Uint32
+ndbGetOwnVersion()
+{
+#ifdef HAVE_NDB_SETVERSION
+ if (ndbOwnVersionTesting == 0)
+ return NDB_VERSION_D;
+ else
+ return ndbOwnVersionTesting;
+#else
+ return NDB_VERSION_D;
+#endif
+}
+
+int
+ndbSearchUpgradeCompatibleTable(Uint32 ownVersion, Uint32 otherVersion,
+ struct NdbUpGradeCompatible table[])
+{
+ int i;
+ for (i = 0; table[i].ownVersion != 0 && table[i].otherVersion != 0; i++) {
+ if (table[i].ownVersion == ownVersion ||
+ table[i].ownVersion == (Uint32) ~0) {
+ switch (table[i].matchType) {
+ case UG_Range:
+ if (otherVersion >= table[i].otherVersion){
+ return 1;
+ }
+ break;
+ case UG_Exact:
+ if (otherVersion == table[i].otherVersion){
+ return 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int
+ndbCompatible(Uint32 ownVersion, Uint32 otherVersion, struct NdbUpGradeCompatible table[])
+{
+ if (otherVersion >= ownVersion) {
+ return 1;
+ }
+ return ndbSearchUpgradeCompatibleTable(ownVersion, otherVersion, table);
+}
+
+int
+ndbCompatible_full(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible(ownVersion, otherVersion, ndbCompatibleTable_full);
+}
+
+int
+ndbCompatible_upgrade(Uint32 ownVersion, Uint32 otherVersion)
+{
+ if (ndbCompatible_full(ownVersion, otherVersion))
+ return 1;
+ return ndbCompatible(ownVersion, otherVersion, ndbCompatibleTable_upgrade);
+}
+
+int
+ndbCompatible_mgmt_ndb(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_upgrade(ownVersion, otherVersion);
+}
+
+int
+ndbCompatible_mgmt_api(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_upgrade(ownVersion, otherVersion);
+}
+
+int
+ndbCompatible_ndb_mgmt(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_full(ownVersion, otherVersion);
+}
+
+int
+ndbCompatible_api_mgmt(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_full(ownVersion, otherVersion);
+}
+
+int
+ndbCompatible_api_ndb(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_full(ownVersion, otherVersion);
+}
+
+int
+ndbCompatible_ndb_api(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_upgrade(ownVersion, otherVersion);
+}
+
+int
+ndbCompatible_ndb_ndb(Uint32 ownVersion, Uint32 otherVersion)
+{
+ return ndbCompatible_upgrade(ownVersion, otherVersion);
+}