/************************************************************************ SQL data field and tuple (c) 1994-1996 Innobase Oy Created 5/30/1994 Heikki Tuuri *************************************************************************/ #include "data0data.h" #ifdef UNIV_NONINL #include "data0data.ic" #endif #include "ut0rnd.h" byte data_error; /* data pointers of tuple fields are initialized to point here for error checking */ ulint data_dummy; /* this is used to fool the compiler in dtuple_validate */ byte data_buf[8192]; /* used in generating test tuples */ ulint data_rnd = 756511; /* Some non-inlined functions used in the MySQL interface: */ void dfield_set_data_noninline( dfield_t* field, /* in: field */ void* data, /* in: data */ ulint len) /* in: length or UNIV_SQL_NULL */ { dfield_set_data(field, data, len); } void* dfield_get_data_noninline( dfield_t* field) /* in: field */ { return(dfield_get_data(field)); } ulint dfield_get_len_noninline( dfield_t* field) /* in: field */ { return(dfield_get_len(field)); } ulint dtuple_get_n_fields_noninline( dtuple_t* tuple) /* in: tuple */ { return(dtuple_get_n_fields(tuple)); } dfield_t* dtuple_get_nth_field_noninline( dtuple_t* tuple, /* in: tuple */ ulint n) /* in: index of field */ { return(dtuple_get_nth_field(tuple, n)); } /************************************************************************* Creates a dtuple for use in MySQL. */ dtuple_t* dtuple_create_for_mysql( /*====================*/ /* out, own created dtuple */ void** heap, /* out: created memory heap */ ulint n_fields) /* in: number of fields */ { *heap = (void*)mem_heap_create(500); return(dtuple_create(*((mem_heap_t**)heap), n_fields)); } /************************************************************************* Frees a dtuple used in MySQL. */ void dtuple_free_for_mysql( /*==================*/ void* heap) /* in: memory heap where tuple was created */ { mem_heap_free((mem_heap_t*)heap); } /************************************************************************* Sets number of fields used in a tuple. Normally this is set in dtuple_create, but if you want later to set it smaller, you can use this. */ void dtuple_set_n_fields( /*================*/ dtuple_t* tuple, /* in: tuple */ ulint n_fields) /* in: number of fields */ { ut_ad(tuple); tuple->n_fields = n_fields; tuple->n_fields_cmp = n_fields; } /************************************************************** Checks that a data field is typed. Asserts an error if not. */ ibool dfield_check_typed( /*===============*/ /* out: TRUE if ok */ dfield_t* field) /* in: data field */ { ut_a(dfield_get_type(field)->mtype <= DATA_MYSQL); ut_a(dfield_get_type(field)->mtype >= DATA_VARCHAR); return(TRUE); } /************************************************************** Checks that a data tuple is typed. Asserts an error if not. */ ibool dtuple_check_typed( /*===============*/ /* out: TRUE if ok */ dtuple_t* tuple) /* in: tuple */ { dfield_t* field; ulint i; for (i = 0; i < dtuple_get_n_fields(tuple); i++) { field = dtuple_get_nth_field(tuple, i); ut_a(dfield_check_typed(field)); } return(TRUE); } /************************************************************** Validates the consistency of a tuple which must be complete, i.e, all fields must have been set. */ ibool dtuple_validate( /*============*/ /* out: TRUE if ok */ dtuple_t* tuple) /* in: tuple */ { dfield_t* field; byte* data; ulint n_fields; ulint len; ulint i; ulint j; ut_a(tuple->magic_n = DATA_TUPLE_MAGIC_N); n_fields = dtuple_get_n_fields(tuple); /* We dereference all the data of each field to test for memory traps */ for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(tuple, i); len = dfield_get_len(field); if (len != UNIV_SQL_NULL) { data = field->data; for (j = 0; j < len; j++) { data_dummy += *data; /* fool the compiler not to optimize out this code */ data++; } } } ut_a(dtuple_check_typed(tuple)); return(TRUE); } /***************************************************************** Pretty prints a dfield value according to its data type. */ void dfield_print( /*=========*/ dfield_t* dfield) /* in: dfield */ { byte* data; ulint len; ulint mtype; ulint i; len = dfield_get_len(dfield); data = dfield_get_data(dfield); if (len == UNIV_SQL_NULL) { printf("NULL"); return; } mtype = dtype_get_mtype(dfield_get_type(dfield)); if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) { for (i = 0; i < len; i++) { if (isprint((char)(*data))) { printf("%c", (char)*data); } else { printf(" "); } data++; } } else if (mtype == DATA_INT) { ut_a(len == 4); /* only works for 32-bit integers */ printf("%i", (int)mach_read_from_4(data)); } else { ut_error; } } /***************************************************************** Pretty prints a dfield value according to its data type. Also the hex string is printed if a string contains non-printable characters. */ void dfield_print_also_hex( /*==================*/ dfield_t* dfield) /* in: dfield */ { byte* data; ulint len; ulint mtype; ulint i; ibool print_also_hex; len = dfield_get_len(dfield); data = dfield_get_data(dfield); if (len == UNIV_SQL_NULL) { printf("NULL"); return; } mtype = dtype_get_mtype(dfield_get_type(dfield)); if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) { print_also_hex = FALSE; for (i = 0; i < len; i++) { if (isprint((char)(*data))) { printf("%c", (char)*data); } else { print_also_hex = TRUE; printf(" "); } data++; } if (!print_also_hex) { return; } printf(" Hex: "); data = dfield_get_data(dfield); for (i = 0; i < len; i++) { printf("%02lx", (ulint)*data); data++; } } else if (mtype == DATA_INT) { ut_a(len == 4); /* inly works for 32-bit integers */ printf("%i", (int)mach_read_from_4(data)); } else { ut_error; } } /************************************************************** The following function prints the contents of a tuple. */ void dtuple_print( /*=========*/ dtuple_t* tuple) /* in: tuple */ { dfield_t* field; ulint n_fields; ulint i; n_fields = dtuple_get_n_fields(tuple); printf("DATA TUPLE: %lu fields;\n", n_fields); for (i = 0; i < n_fields; i++) { printf(" %lu:", i); field = dtuple_get_nth_field(tuple, i); if (field->len != UNIV_SQL_NULL) { ut_print_buf(field->data, field->len); } else { printf(" SQL NULL"); } printf(";"); } printf("\n"); dtuple_validate(tuple); } /************************************************************** The following function prints the contents of a tuple to a buffer. */ ulint dtuple_sprintf( /*===========*/ /* out: printed length in bytes */ char* buf, /* in: print buffer */ ulint buf_len,/* in: buf length in bytes */ dtuple_t* tuple) /* in: tuple */ { dfield_t* field; ulint n_fields; ulint len; ulint i; len = 0; n_fields = dtuple_get_n_fields(tuple); for (i = 0; i < n_fields; i++) { if (len + 30 > buf_len) { return(len); } len += sprintf(buf + len, " %lu:", i); field = dtuple_get_nth_field(tuple, i); if (field->len != UNIV_SQL_NULL) { if (5 * field->len + len + 30 > buf_len) { return(len); } len += ut_sprintf_buf(buf + len, field->data, field->len); } else { len += sprintf(buf + len, " SQL NULL"); } len += sprintf(buf + len, ";"); } return(len); } #ifdef notdefined /****************************************************************** Generates random numbers, where 10/16 is uniformly distributed between 0 and n1, 5/16 between 0 and n2, and 1/16 between 0 and n3. */ static ulint dtuple_gen_rnd_ulint( /*=================*/ /* out: random ulint */ ulint n1, ulint n2, ulint n3) { ulint m; ulint n; m = ut_rnd_gen_ulint() % 16; if (m < 10) { n = n1; } else if (m < 15) { n = n2; } else { n = n3; } m = ut_rnd_gen_ulint(); return(m % n); } /*************************************************************** Generates a random tuple. */ dtuple_t* dtuple_gen_rnd_tuple( /*=================*/ /* out: pointer to the tuple */ mem_heap_t* heap) /* in: memory heap where generated */ { ulint n_fields; dfield_t* field; ulint len; dtuple_t* tuple; ulint i; ulint j; byte* ptr; n_fields = dtuple_gen_rnd_ulint(5, 30, 300) + 1; tuple = dtuple_create(heap, n_fields); for (i = 0; i < n_fields; i++) { if (n_fields < 7) { len = dtuple_gen_rnd_ulint(5, 30, 400); } else { len = dtuple_gen_rnd_ulint(7, 5, 17); } field = dtuple_get_nth_field(tuple, i); if (len == 0) { dfield_set_data(field, NULL, UNIV_SQL_NULL); } else { ptr = mem_heap_alloc(heap, len); dfield_set_data(field, ptr, len - 1); for (j = 0; j < len; j++) { *ptr = (byte)(65 + dtuple_gen_rnd_ulint(22, 22, 22)); ptr++; } } dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 500, 0); } ut_a(dtuple_validate(tuple)); return(tuple); } /******************************************************************* Generates a test tuple for sort and comparison tests. */ void dtuple_gen_test_tuple( /*==================*/ dtuple_t* tuple, /* in/out: a tuple with 3 fields */ ulint i) /* in: a number < 512 */ { ulint j; dfield_t* field; void* data = NULL; ulint len = 0; for (j = 0; j < 3; j++) { switch (i % 8) { case 0: data = ""; len = 0; break; case 1: data = "A"; len = 1; break; case 2: data = "AA"; len = 2; break; case 3: data = "AB"; len = 2; break; case 4: data = "B"; len = 1; break; case 5: data = "BA"; len = 2; break; case 6: data = "BB"; len = 2; break; case 7: len = UNIV_SQL_NULL; break; } field = dtuple_get_nth_field(tuple, 2 - j); dfield_set_data(field, data, len); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); i = i / 8; } ut_ad(dtuple_validate(tuple)); } /******************************************************************* Generates a test tuple for B-tree speed tests. */ void dtuple_gen_test_tuple3( /*===================*/ dtuple_t* tuple, /* in/out: a tuple with >= 3 fields */ ulint i, /* in: a number < 1000000 */ ulint type, /* in: DTUPLE_TEST_FIXED30, ... */ byte* buf) /* in: a buffer of size >= 16 bytes */ { dfield_t* field; ulint third_size; ut_ad(tuple && buf); ut_ad(i < 1000000); field = dtuple_get_nth_field(tuple, 0); ut_strcpy((char*)buf, "0000000"); buf[1] = (byte)('0' + (i / 100000) % 10); buf[2] = (byte)('0' + (i / 10000) % 10); buf[3] = (byte)('0' + (i / 1000) % 10); buf[4] = (byte)('0' + (i / 100) % 10); buf[5] = (byte)('0' + (i / 10) % 10); buf[6] = (byte)('0' + (i % 10)); dfield_set_data(field, buf, 8); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); field = dtuple_get_nth_field(tuple, 1); i = i % 1000; /* ut_rnd_gen_ulint() % 1000000; */ ut_strcpy((char*)buf + 8, "0000000"); buf[9] = (byte)('0' + (i / 100000) % 10); buf[10] = (byte)('0' + (i / 10000) % 10); buf[11] = (byte)('0' + (i / 1000) % 10); buf[12] = (byte)('0' + (i / 100) % 10); buf[13] = (byte)('0' + (i / 10) % 10); buf[14] = (byte)('0' + (i % 10)); dfield_set_data(field, buf + 8, 8); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); field = dtuple_get_nth_field(tuple, 2); data_rnd += 8757651; if (type == DTUPLE_TEST_FIXED30) { third_size = 30; } else if (type == DTUPLE_TEST_RND30) { third_size = data_rnd % 30; } else if (type == DTUPLE_TEST_RND3500) { third_size = data_rnd % 3500; } else if (type == DTUPLE_TEST_FIXED2000) { third_size = 2000; } else if (type == DTUPLE_TEST_FIXED3) { third_size = 3; } else { ut_error; } if (type == DTUPLE_TEST_FIXED30) { dfield_set_data(field, "12345678901234567890123456789", third_size); } else { dfield_set_data(field, data_buf, third_size); } dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); ut_ad(dtuple_validate(tuple)); } /******************************************************************* Generates a test tuple for B-tree speed tests. */ void dtuple_gen_search_tuple3( /*=====================*/ dtuple_t* tuple, /* in/out: a tuple with 1 or 2 fields */ ulint i, /* in: a number < 1000000 */ byte* buf) /* in: a buffer of size >= 16 bytes */ { dfield_t* field; ut_ad(tuple && buf); ut_ad(i < 1000000); field = dtuple_get_nth_field(tuple, 0); ut_strcpy((char*)buf, "0000000"); buf[1] = (byte)('0' + (i / 100000) % 10); buf[2] = (byte)('0' + (i / 10000) % 10); buf[3] = (byte)('0' + (i / 1000) % 10); buf[4] = (byte)('0' + (i / 100) % 10); buf[5] = (byte)('0' + (i / 10) % 10); buf[6] = (byte)('0' + (i % 10)); dfield_set_data(field, buf, 8); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); if (dtuple_get_n_fields(tuple) == 1) { return; } field = dtuple_get_nth_field(tuple, 1); i = (i * 1000) % 1000000; ut_strcpy((char*)buf + 8, "0000000"); buf[9] = (byte)('0' + (i / 100000) % 10); buf[10] = (byte)('0' + (i / 10000) % 10); buf[11] = (byte)('0' + (i / 1000) % 10); buf[12] = (byte)('0' + (i / 100) % 10); buf[13] = (byte)('0' + (i / 10) % 10); buf[14] = (byte)('0' + (i % 10)); dfield_set_data(field, buf + 8, 8); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); ut_ad(dtuple_validate(tuple)); } /******************************************************************* Generates a test tuple for TPC-A speed test. */ void dtuple_gen_test_tuple_TPC_A( /*========================*/ dtuple_t* tuple, /* in/out: a tuple with >= 3 fields */ ulint i, /* in: a number < 10000 */ byte* buf) /* in: a buffer of size >= 16 bytes */ { dfield_t* field; ulint third_size; ut_ad(tuple && buf); ut_ad(i < 10000); field = dtuple_get_nth_field(tuple, 0); ut_strcpy((char*)buf, "0000"); buf[0] = (byte)('0' + (i / 1000) % 10); buf[1] = (byte)('0' + (i / 100) % 10); buf[2] = (byte)('0' + (i / 10) % 10); buf[3] = (byte)('0' + (i % 10)); dfield_set_data(field, buf, 5); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); field = dtuple_get_nth_field(tuple, 1); dfield_set_data(field, buf + 8, 5); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); field = dtuple_get_nth_field(tuple, 2); third_size = 90; dfield_set_data(field, data_buf, third_size); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); ut_ad(dtuple_validate(tuple)); } /******************************************************************* Generates a test tuple for B-tree speed tests. */ void dtuple_gen_search_tuple_TPC_A( /*==========================*/ dtuple_t* tuple, /* in/out: a tuple with 1 field */ ulint i, /* in: a number < 10000 */ byte* buf) /* in: a buffer of size >= 16 bytes */ { dfield_t* field; ut_ad(tuple && buf); ut_ad(i < 10000); field = dtuple_get_nth_field(tuple, 0); ut_strcpy((char*)buf, "0000"); buf[0] = (byte)('0' + (i / 1000) % 10); buf[1] = (byte)('0' + (i / 100) % 10); buf[2] = (byte)('0' + (i / 10) % 10); buf[3] = (byte)('0' + (i % 10)); dfield_set_data(field, buf, 5); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); ut_ad(dtuple_validate(tuple)); } /******************************************************************* Generates a test tuple for TPC-C speed test. */ void dtuple_gen_test_tuple_TPC_C( /*========================*/ dtuple_t* tuple, /* in/out: a tuple with >= 12 fields */ ulint i, /* in: a number < 100000 */ byte* buf) /* in: a buffer of size >= 16 bytes */ { dfield_t* field; ulint size; ulint j; ut_ad(tuple && buf); ut_ad(i < 100000); field = dtuple_get_nth_field(tuple, 0); buf[0] = (byte)('0' + (i / 10000) % 10); buf[1] = (byte)('0' + (i / 1000) % 10); buf[2] = (byte)('0' + (i / 100) % 10); buf[3] = (byte)('0' + (i / 10) % 10); buf[4] = (byte)('0' + (i % 10)); dfield_set_data(field, buf, 5); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); field = dtuple_get_nth_field(tuple, 1); dfield_set_data(field, buf, 5); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); for (j = 0; j < 10; j++) { field = dtuple_get_nth_field(tuple, 2 + j); size = 24; dfield_set_data(field, data_buf, size); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); } ut_ad(dtuple_validate(tuple)); } /******************************************************************* Generates a test tuple for B-tree speed tests. */ void dtuple_gen_search_tuple_TPC_C( /*==========================*/ dtuple_t* tuple, /* in/out: a tuple with 1 field */ ulint i, /* in: a number < 100000 */ byte* buf) /* in: a buffer of size >= 16 bytes */ { dfield_t* field; ut_ad(tuple && buf); ut_ad(i < 100000); field = dtuple_get_nth_field(tuple, 0); buf[0] = (byte)('0' + (i / 10000) % 10); buf[1] = (byte)('0' + (i / 1000) % 10); buf[2] = (byte)('0' + (i / 100) % 10); buf[3] = (byte)('0' + (i / 10) % 10); buf[4] = (byte)('0' + (i % 10)); dfield_set_data(field, buf, 5); dtype_set(dfield_get_type(field), DATA_VARCHAR, DATA_ENGLISH, 100, 0); ut_ad(dtuple_validate(tuple)); } #endif /* notdefined */