17
17
/* Some general useful functions */
19
#include <drizzled/server_includes.h>
28
20
#include <drizzled/error.h>
29
21
#include <drizzled/gettext.h>
31
#include "drizzled/plugin/transactional_storage_engine.h"
32
#include "drizzled/plugin/authorization.h"
23
#include <drizzled/sj_tmp_table.h>
33
24
#include <drizzled/nested_join.h>
25
#include <drizzled/data_home.h>
34
26
#include <drizzled/sql_parse.h>
35
27
#include <drizzled/item/sum.h>
28
#include <drizzled/virtual_column_info.h>
36
29
#include <drizzled/table_list.h>
37
30
#include <drizzled/session.h>
38
31
#include <drizzled/sql_base.h>
39
#include <drizzled/sql_select.h>
40
32
#include <drizzled/field/blob.h>
41
33
#include <drizzled/field/varstring.h>
42
34
#include <drizzled/field/double.h>
43
38
#include <drizzled/unireg.h>
44
39
#include <drizzled/message/table.pb.h>
45
#include "drizzled/sql_table.h"
46
#include "drizzled/charset.h"
47
#include "drizzled/internal/m_string.h"
48
#include "plugin/myisam/myisam.h"
50
41
#include <drizzled/item/string.h>
51
42
#include <drizzled/item/int.h>
52
43
#include <drizzled/item/decimal.h>
53
44
#include <drizzled/item/float.h>
54
45
#include <drizzled/item/null.h>
55
#include <drizzled/temporal.h>
57
#include "drizzled/table_proto.h"
59
48
using namespace std;
64
extern pid_t current_pid;
65
extern plugin::StorageEngine *heap_engine;
66
extern plugin::StorageEngine *myisam_engine;
68
/* Functions defined in this cursor */
70
void open_table_error(TableShare *share, int error, int db_errno,
50
/* Keyword for parsing virtual column functions */
51
LEX_STRING parse_vcol_keyword= { C_STRING_WITH_LEN("PARSE_VCOL_EXPR ") };
53
/* Functions defined in this file */
55
void open_table_error(TABLE_SHARE *share, int error, int db_errno,
71
56
myf errortype, int errarg);
57
static void fix_type_pointers(const char ***array, TYPELIB *point_to_type,
58
uint32_t types, char **names);
73
60
/*************************************************************************/
97
TableShare *alloc_table_share(TableList *table_list, char *key,
131
TABLE_SHARE *alloc_table_share(TableList *table_list, char *key,
98
132
uint32_t key_length)
100
memory::Root mem_root;
102
136
char *key_buff, *path_buff;
105
build_table_filename(path, table_list->db, table_list->table_name, false);
107
memory::init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
137
char path[FN_REFLEN];
138
uint32_t path_length;
140
path_length= build_table_filename(path, sizeof(path) - 1,
142
table_list->table_name, "", 0);
143
init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
108
144
if (multi_alloc_root(&mem_root,
109
145
&share, sizeof(*share),
110
146
&key_buff, key_length,
111
&path_buff, path.length() + 1,
147
&path_buff, path_length + 1,
114
150
memset(share, 0, sizeof(*share));
116
152
share->set_table_cache_key(key_buff, key, key_length);
118
share->path.str= path_buff,
119
share->path.length= path.length();
120
strcpy(share->path.str, path.c_str());
154
share->path.str= path_buff;
155
share->path.length= path_length;
156
strcpy(share->path.str, path);
121
157
share->normalized_path.str= share->path.str;
122
share->normalized_path.length= path.length();
158
share->normalized_path.length= path_length;
124
160
share->version= refresh_version;
163
This constant is used to mark that no table map version has been
164
assigned. No arithmetic is done on the value: it will be
165
overwritten with a value taken from DRIZZLE_BIN_LOG.
167
share->table_map_version= UINT64_MAX;
170
Since alloc_table_share() can be called without any locking (for
171
example, ha_create_table... functions), we do not assign a table
172
map id here. Instead we assign a value that is not used
173
elsewhere, and then assign a table map id inside open_table()
174
under the protection of the LOCK_open mutex.
176
share->table_map_id= UINT32_MAX;
177
share->cached_row_logging_check= -1;
126
179
memcpy(&share->mem_root, &mem_root, sizeof(mem_root));
127
180
pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
128
181
pthread_cond_init(&share->cond, NULL);
134
static enum_field_types proto_field_type_to_drizzle_type(uint32_t proto_field_type)
188
Initialize share for temporary tables
191
init_tmp_table_share()
192
session thread handle
194
key Table_cache_key, as generated from create_table_def_key.
195
must start with db name.
196
key_length Length of key
197
table_name Table name
198
path Path to file (possible in lower case) without .frm
201
This is different from alloc_table_share() because temporary tables
202
don't have to be shared between threads or put into the table def
203
cache, so we can do some things notable simpler and faster
205
If table is not put in session->temporary_tables (happens only when
206
one uses OPEN TEMPORARY) then one can specify 'db' as key and
207
use key_length= 0 as neither table_cache_key or key_length will be used).
210
void init_tmp_table_share(Session *session, TABLE_SHARE *share, const char *key,
211
uint32_t key_length, const char *table_name,
215
memset(share, 0, sizeof(*share));
216
init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
217
share->table_category= TABLE_CATEGORY_TEMPORARY;
218
share->tmp_table= INTERNAL_TMP_TABLE;
219
share->db.str= (char*) key;
220
share->db.length= strlen(key);
221
share->table_cache_key.str= (char*) key;
222
share->table_cache_key.length= key_length;
223
share->table_name.str= (char*) table_name;
224
share->table_name.length= strlen(table_name);
225
share->path.str= (char*) path;
226
share->normalized_path.str= (char*) path;
227
share->path.length= share->normalized_path.length= strlen(path);
230
Temporary tables are not replicated, but we set up these fields
231
anyway to be able to catch errors.
233
share->table_map_version= ~(uint64_t)0;
234
share->cached_row_logging_check= -1;
237
table_map_id is also used for MERGE tables to suppress repeated
238
compatibility checks.
240
share->table_map_id= (ulong) session->query_id;
247
Free table share and memory used by it
254
share->mutex must be locked when we come here if it's not a temp table
257
void free_table_share(TABLE_SHARE *share)
260
assert(share->ref_count == 0);
263
If someone is waiting for this to be deleted, inform it about this.
264
Don't do a delete until we know that no one is refering to this anymore.
266
if (share->tmp_table == NO_TMP_TABLE)
268
/* share->mutex is locked in release_table_share() */
269
while (share->waiting_on_cond)
271
pthread_cond_broadcast(&share->cond);
272
pthread_cond_wait(&share->cond, &share->mutex);
274
/* No thread refers to this anymore */
275
pthread_mutex_unlock(&share->mutex);
276
pthread_mutex_destroy(&share->mutex);
277
pthread_cond_destroy(&share->cond);
279
hash_free(&share->name_hash);
281
share->storage_engine= NULL;
283
/* We must copy mem_root from share because share is allocated through it */
284
memcpy(&mem_root, &share->mem_root, sizeof(mem_root));
285
free_root(&mem_root, MYF(0)); // Free's share
289
enum_field_types proto_field_type_to_drizzle_type(uint32_t proto_field_type)
136
291
enum_field_types field_type;
138
293
switch(proto_field_type)
140
case message::Table::Field::INTEGER:
295
case drizzled::message::Table::Field::TINYINT:
296
field_type= DRIZZLE_TYPE_TINY;
298
case drizzled::message::Table::Field::INTEGER:
141
299
field_type= DRIZZLE_TYPE_LONG;
143
case message::Table::Field::DOUBLE:
301
case drizzled::message::Table::Field::DOUBLE:
144
302
field_type= DRIZZLE_TYPE_DOUBLE;
146
case message::Table::Field::TIMESTAMP:
304
case drizzled::message::Table::Field::TIMESTAMP:
147
305
field_type= DRIZZLE_TYPE_TIMESTAMP;
149
case message::Table::Field::BIGINT:
307
case drizzled::message::Table::Field::BIGINT:
150
308
field_type= DRIZZLE_TYPE_LONGLONG;
152
case message::Table::Field::DATETIME:
310
case drizzled::message::Table::Field::DATETIME:
153
311
field_type= DRIZZLE_TYPE_DATETIME;
155
case message::Table::Field::DATE:
313
case drizzled::message::Table::Field::DATE:
156
314
field_type= DRIZZLE_TYPE_DATE;
158
case message::Table::Field::VARCHAR:
316
case drizzled::message::Table::Field::VARCHAR:
159
317
field_type= DRIZZLE_TYPE_VARCHAR;
161
case message::Table::Field::DECIMAL:
162
field_type= DRIZZLE_TYPE_DECIMAL;
319
case drizzled::message::Table::Field::DECIMAL:
320
field_type= DRIZZLE_TYPE_NEWDECIMAL;
164
case message::Table::Field::ENUM:
322
case drizzled::message::Table::Field::ENUM:
165
323
field_type= DRIZZLE_TYPE_ENUM;
167
case message::Table::Field::BLOB:
325
case drizzled::message::Table::Field::BLOB:
168
326
field_type= DRIZZLE_TYPE_BLOB;
328
case drizzled::message::Table::Field::VIRTUAL:
329
field_type= DRIZZLE_TYPE_VIRTUAL;
171
field_type= DRIZZLE_TYPE_LONG; /* Set value to kill GCC warning */
332
field_type= DRIZZLE_TYPE_TINY; /* Set value to kill GCC warning */
175
336
return field_type;
178
static Item *default_value_item(enum_field_types field_type,
179
const CHARSET_INFO *charset,
180
bool default_null, const string *default_value,
181
const string *default_bin_value)
339
Item * default_value_item(enum_field_types field_type,
340
const CHARSET_INFO *charset,
341
bool default_null, const string *default_value,
342
const string *default_bin_value)
183
344
Item *default_item= NULL;
188
349
return new Item_null();
191
352
switch(field_type)
354
case DRIZZLE_TYPE_TINY:
193
355
case DRIZZLE_TYPE_LONG:
194
356
case DRIZZLE_TYPE_LONGLONG:
195
357
default_item= new Item_int(default_value->c_str(),
196
(int64_t) internal::my_strtoll10(default_value->c_str(),
358
(int64_t) my_strtoll10(default_value->c_str(),
199
361
default_value->length());
201
363
case DRIZZLE_TYPE_DOUBLE:
239
403
return default_item;
242
int parse_table_proto(Session& session,
243
message::Table &table,
406
int parse_table_proto(Session *session, drizzled::message::Table &table, TABLE_SHARE *share)
409
handler *handler_file= NULL;
248
if (! table.IsInitialized())
250
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), table.InitializationErrorString().c_str());
251
return ER_CORRUPT_TABLE_DEFINITION;
412
LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
413
strlen(table.engine().name().c_str()) };
414
share->storage_engine= ha_resolve_by_name(session, &engine_name);
254
share->setTableProto(new(nothrow) message::Table(table));
256
share->storage_engine= plugin::StorageEngine::findByName(session, table.engine().name());
257
assert(share->storage_engine); // We use an assert() here because we should never get this far and still have no suitable engine.
259
message::Table::TableOptions table_options;
261
if (table.has_options())
417
share->mysql_version= DRIZZLE_VERSION_ID; // TODO: remove
419
drizzled::message::Table::TableOptions table_options;
421
if(table.has_options())
262
422
table_options= table.options();
264
uint32_t db_create_options= 0;
424
uint32_t db_create_options= HA_OPTION_LONG_BLOB_PTR;
266
if (table_options.has_pack_keys())
426
if(table_options.has_pack_keys())
268
if (table_options.pack_keys())
428
if(table_options.pack_keys())
269
429
db_create_options|= HA_OPTION_PACK_KEYS;
271
431
db_create_options|= HA_OPTION_NO_PACK_KEYS;
274
if (table_options.pack_record())
434
if(table_options.pack_record())
275
435
db_create_options|= HA_OPTION_PACK_RECORD;
437
if(table_options.has_checksum())
439
if(table_options.checksum())
440
db_create_options|= HA_OPTION_CHECKSUM;
442
db_create_options|= HA_OPTION_NO_CHECKSUM;
445
if(table_options.has_delay_key_write())
447
if(table_options.delay_key_write())
448
db_create_options|= HA_OPTION_DELAY_KEY_WRITE;
450
db_create_options|= HA_OPTION_NO_DELAY_KEY_WRITE;
277
453
/* db_create_options was stored as 2 bytes in FRM
278
454
Any HA_OPTION_ that doesn't fit into 2 bytes was silently truncated away.
280
456
share->db_create_options= (db_create_options & 0x0000FFFF);
281
457
share->db_options_in_use= share->db_create_options;
460
share->avg_row_length= table_options.has_avg_row_length() ?
461
table_options.avg_row_length() : 0;
463
share->page_checksum= table_options.has_page_checksum() ?
464
(table_options.page_checksum()?HA_CHOICE_YES:HA_CHOICE_NO)
283
467
share->row_type= table_options.has_row_type() ?
284
468
(enum row_type) table_options.row_type() : ROW_TYPE_DEFAULT;
340
532
share->keynames.type_lengths[share->keynames.count]= 0;
342
534
KEY* keyinfo= share->key_info;
343
for (int keynr= 0; keynr < table.indexes_size(); keynr++, keyinfo++)
535
for (int keynr=0; keynr < table.indexes_size(); keynr++, keyinfo++)
345
message::Table::Index indx= table.indexes(keynr);
537
drizzled::message::Table::Index indx= table.indexes(keynr);
347
539
keyinfo->table= 0;
348
540
keyinfo->flags= 0;
350
if (indx.is_unique())
351
543
keyinfo->flags|= HA_NOSAME;
353
if (indx.has_options())
545
if(indx.has_options())
355
message::Table::Index::IndexOptions indx_options= indx.options();
356
if (indx_options.pack_key())
357
keyinfo->flags|= HA_PACK_KEY;
359
if (indx_options.var_length_key())
360
keyinfo->flags|= HA_VAR_LENGTH_PART;
362
if (indx_options.null_part_key())
363
keyinfo->flags|= HA_NULL_PART_KEY;
365
if (indx_options.binary_pack_key())
366
keyinfo->flags|= HA_BINARY_PACK_KEY;
368
if (indx_options.has_partial_segments())
369
keyinfo->flags|= HA_KEY_HAS_PART_KEY_SEG;
371
if (indx_options.auto_generated_key())
372
keyinfo->flags|= HA_GENERATED_KEY;
374
if (indx_options.has_key_block_size())
547
drizzled::message::Table::Index::IndexOptions indx_options= indx.options();
548
if(indx_options.pack_key())
549
keyinfo->flags|= HA_PACK_KEY;
551
if(indx_options.var_length_key())
552
keyinfo->flags|= HA_VAR_LENGTH_PART;
554
if(indx_options.null_part_key())
555
keyinfo->flags|= HA_NULL_PART_KEY;
557
if(indx_options.binary_pack_key())
558
keyinfo->flags|= HA_BINARY_PACK_KEY;
560
if(indx_options.has_partial_segments())
561
keyinfo->flags|= HA_KEY_HAS_PART_KEY_SEG;
563
if(indx_options.auto_generated_key())
564
keyinfo->flags|= HA_GENERATED_KEY;
566
if(indx_options.has_key_block_size())
376
keyinfo->flags|= HA_USES_BLOCK_SIZE;
377
keyinfo->block_size= indx_options.key_block_size();
568
keyinfo->flags|= HA_USES_BLOCK_SIZE;
569
keyinfo->block_size= indx_options.key_block_size();
381
keyinfo->block_size= 0;
573
keyinfo->block_size= 0;
387
case message::Table::Index::UNKNOWN_INDEX:
580
case drizzled::message::Table::Index::UNKNOWN_INDEX:
388
581
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
390
case message::Table::Index::BTREE:
583
case drizzled::message::Table::Index::BTREE:
391
584
keyinfo->algorithm= HA_KEY_ALG_BTREE;
393
case message::Table::Index::HASH:
586
case drizzled::message::Table::Index::RTREE:
587
keyinfo->algorithm= HA_KEY_ALG_RTREE;
589
case drizzled::message::Table::Index::HASH:
394
590
keyinfo->algorithm= HA_KEY_ALG_HASH;
592
case drizzled::message::Table::Index::FULLTEXT:
593
keyinfo->algorithm= HA_KEY_ALG_FULLTEXT;
398
596
/* TODO: suitable warning ? */
744
1004
enum_field_types field_type;
1005
virtual_column_info *vcol_info= NULL;
1006
bool field_is_stored= true;
746
1009
field_type= proto_field_type_to_drizzle_type(pfield.type());
1011
if(field_type==DRIZZLE_TYPE_VIRTUAL)
1013
drizzled::message::Table::Field::VirtualFieldOptions field_options=
1014
pfield.virtual_options();
1016
vcol_info= new virtual_column_info();
1017
field_type= proto_field_type_to_drizzle_type(field_options.type());
1018
field_is_stored= field_options.physically_stored();
1020
size_t len= field_options.expression().length();
1021
const char* str= field_options.expression().c_str();
1023
vcol_info->expr_str.str= strmake_root(&share->mem_root, str, len);
1024
vcol_info->expr_str.length= len;
748
1029
const CHARSET_INFO *charset= &my_charset_bin;
750
if (field_type == DRIZZLE_TYPE_BLOB ||
751
field_type == DRIZZLE_TYPE_VARCHAR)
753
message::Table::Field::StringFieldOptions field_options= pfield.string_options();
755
charset= get_charset(field_options.has_collation_id() ?
756
field_options.collation_id() : 0);
759
charset= default_charset_info;
762
if (field_type == DRIZZLE_TYPE_ENUM)
764
message::Table::Field::EnumerationValues field_options= pfield.enumeration_values();
766
charset= get_charset(field_options.has_collation_id()?
767
field_options.collation_id() : 0);
770
charset= default_charset_info;
774
if (field_type == DRIZZLE_TYPE_DECIMAL
775
|| field_type == DRIZZLE_TYPE_DOUBLE)
777
message::Table::Field::NumericFieldOptions fo= pfield.numeric_options();
779
if (! pfield.has_numeric_options() || ! fo.has_scale())
782
We don't write the default to table proto so
783
if no decimals specified for DOUBLE, we use the default.
785
decimals= NOT_FIXED_DEC;
789
if (fo.scale() > DECIMAL_MAX_SCALE)
794
decimals= static_cast<uint8_t>(fo.scale());
1031
if(field_type==DRIZZLE_TYPE_BLOB
1032
|| field_type==DRIZZLE_TYPE_VARCHAR)
1034
drizzled::message::Table::Field::StringFieldOptions field_options=
1035
pfield.string_options();
1037
charset= get_charset(field_options.has_collation_id()?
1038
field_options.collation_id() : 0);
1041
charset= default_charset_info;
1045
if(field_type==DRIZZLE_TYPE_ENUM)
1047
drizzled::message::Table::Field::SetFieldOptions field_options=
1048
pfield.set_options();
1050
charset= get_charset(field_options.has_collation_id()?
1051
field_options.collation_id() : 0);
1054
charset= default_charset_info;
798
1058
Item *default_value= NULL;
800
if (pfield.options().has_default_value() ||
801
pfield.options().has_default_null() ||
802
pfield.options().has_default_bin_value())
1060
if(pfield.options().has_default_value()
1061
|| pfield.options().has_default_null()
1062
|| pfield.options().has_default_bin_value())
804
1064
default_value= default_value_item(field_type,
806
pfield.options().default_null(),
807
&pfield.options().default_value(),
808
&pfield.options().default_bin_value());
1066
pfield.options().default_null(),
1067
&pfield.options().default_value(),
1068
&pfield.options().default_bin_value());
1071
uint32_t pack_flag= pfield.pack_flag(); /* TODO: MUST DIE */
812
1073
Table temp_table; /* Use this so that BLOB DEFAULT '' works */
813
1074
memset(&temp_table, 0, sizeof(temp_table));
814
1075
temp_table.s= share;
815
temp_table.in_use= &session;
816
temp_table.s->db_low_byte_first= true; //Cursor->low_byte_first();
1076
temp_table.in_use= session;
1077
temp_table.s->db_low_byte_first= 1; //handler->low_byte_first();
817
1078
temp_table.s->blob_ptr_size= portable_sizeof_char_ptr;
819
uint32_t field_length= 0; //Assignment is for compiler complaint.
823
case DRIZZLE_TYPE_BLOB:
824
case DRIZZLE_TYPE_VARCHAR:
826
message::Table::Field::StringFieldOptions field_options= pfield.string_options();
828
charset= get_charset(field_options.has_collation_id() ?
829
field_options.collation_id() : 0);
832
charset= default_charset_info;
834
field_length= field_options.length() * charset->mbmaxlen;
837
case DRIZZLE_TYPE_DOUBLE:
839
message::Table::Field::NumericFieldOptions fo= pfield.numeric_options();
840
if (!fo.has_precision() && !fo.has_scale())
842
field_length= DBL_DIG+7;
846
field_length= fo.precision();
848
if (field_length < decimals &&
849
decimals != NOT_FIXED_DEC)
851
my_error(ER_M_BIGGER_THAN_D, MYF(0), pfield.name().c_str());
857
case DRIZZLE_TYPE_DECIMAL:
859
message::Table::Field::NumericFieldOptions fo= pfield.numeric_options();
861
field_length= my_decimal_precision_to_length(fo.precision(), fo.scale(),
865
case DRIZZLE_TYPE_TIMESTAMP:
866
case DRIZZLE_TYPE_DATETIME:
867
field_length= DateTime::MAX_STRING_LENGTH;
869
case DRIZZLE_TYPE_DATE:
870
field_length= Date::MAX_STRING_LENGTH;
872
case DRIZZLE_TYPE_ENUM:
876
message::Table::Field::EnumerationValues fo= pfield.enumeration_values();
878
for (int valnr= 0; valnr < fo.field_value_size(); valnr++)
880
if (fo.field_value(valnr).length() > field_length)
882
field_length= charset->cset->numchars(charset,
883
fo.field_value(valnr).c_str(),
884
fo.field_value(valnr).c_str()
885
+ fo.field_value(valnr).length())
891
case DRIZZLE_TYPE_LONG:
893
uint32_t sign_len= pfield.constraints().is_unsigned() ? 0 : 1;
894
field_length= MAX_INT_WIDTH+sign_len;
897
case DRIZZLE_TYPE_LONGLONG:
898
field_length= MAX_BIGINT_WIDTH;
900
case DRIZZLE_TYPE_NULL:
901
abort(); // Programming error
904
Field* f= make_field(share,
906
record + field_offsets[fieldnr] + data_offset,
908
pfield.constraints().is_nullable(),
914
(Field::utype) MTYP_TYPENR(unireg_type),
915
((field_type == DRIZZLE_TYPE_ENUM) ?
916
share->intervals + (interval_nr++)
918
share->fieldnames.type_names[fieldnr]);
1080
Field* f= make_field(share, &share->mem_root,
1081
record+field_offsets[fieldnr]+data_offset,
1082
pfield.options().length(),
1088
(Field::utype) MTYP_TYPENR(unireg_type),
1089
((field_type==DRIZZLE_TYPE_ENUM)?
1090
share->intervals+(interval_nr++)
1092
share->fieldnames.type_names[fieldnr]);
920
1094
share->field[fieldnr]= f;
922
1096
f->init(&temp_table); /* blob default values need table obj */
924
if (! (f->flags & NOT_NULL_FLAG))
1098
if(!(f->flags & NOT_NULL_FLAG))
926
1100
*f->null_ptr|= f->null_bit;
927
if (! (null_bit_pos= (null_bit_pos + 1) & 7)) /* @TODO Ugh. */
1101
if (!(null_bit_pos= (null_bit_pos + 1) & 7))
934
enum_check_fields old_count_cuted_fields= session.count_cuted_fields;
935
session.count_cuted_fields= CHECK_FIELD_WARN;
1108
enum_check_fields old_count_cuted_fields= session->count_cuted_fields;
1109
session->count_cuted_fields= CHECK_FIELD_WARN;
936
1110
int res= default_value->save_in_field(f, 1);
937
session.count_cuted_fields= old_count_cuted_fields;
938
if (res != 0 && res != 3) /* @TODO Huh? */
1111
session->count_cuted_fields= old_count_cuted_fields;
1112
if (res != 0 && res != 3)
940
1114
my_error(ER_INVALID_DEFAULT, MYF(0), f->field_name);
945
else if (f->real_type() == DRIZZLE_TYPE_ENUM &&
946
(f->flags & NOT_NULL_FLAG))
1119
else if(f->real_type() == DRIZZLE_TYPE_ENUM &&
1120
(f->flags & NOT_NULL_FLAG))
948
1122
f->set_notnull();
949
1123
f->store((int64_t) 1, true);
1003
1179
if (null_count & 7)
1004
1180
*(record + null_count / 8)|= ~(((unsigned char) 1 << (null_count & 7)) - 1);
1006
share->null_bytes= (null_pos - (unsigned char*) record + (null_bit_pos + 7) / 8);
1182
share->null_bytes= (null_pos - (unsigned char*) record +
1183
(null_bit_pos + 7) / 8);
1008
1185
share->last_null_bit_pos= null_bit_pos;
1010
1187
free(field_offsets);
1011
field_offsets= NULL;
1012
1188
free(field_pack_length);
1013
field_pack_length= NULL;
1190
if(!(handler_file= get_new_handler(share, session->mem_root,
1015
1194
/* Fix key stuff */
1016
1195
if (share->key_parts)
1018
uint32_t primary_key= (uint32_t) (find_type((char*) "PRIMARY",
1019
&share->keynames, 3) - 1); /* @TODO Huh? */
1197
uint32_t primary_key=(uint32_t) (find_type((char*) "PRIMARY",
1198
&share->keynames, 3) - 1);
1200
int64_t ha_option= handler_file->ha_table_flags();
1021
1202
keyinfo= share->key_info;
1022
1203
key_part= keyinfo->key_part;
1024
for (uint32_t key= 0; key < share->keys; key++,keyinfo++)
1205
for (uint32_t key=0 ; key < share->keys ; key++,keyinfo++)
1026
1207
uint32_t usable_parts= 0;
1028
1209
if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
1031
If the UNIQUE key doesn't have NULL columns and is not a part key
1032
declare this as a primary key.
1035
for (uint32_t i= 0; i < keyinfo->key_parts; i++)
1037
uint32_t fieldnr= key_part[i].fieldnr;
1039
share->field[fieldnr-1]->null_ptr ||
1040
share->field[fieldnr-1]->key_length() != key_part[i].length)
1042
primary_key= MAX_KEY; // Can't be used
1212
If the UNIQUE key doesn't have NULL columns and is not a part key
1213
declare this as a primary key.
1216
for (uint32_t i=0 ; i < keyinfo->key_parts ;i++)
1218
uint32_t fieldnr= key_part[i].fieldnr;
1220
share->field[fieldnr-1]->null_ptr ||
1221
share->field[fieldnr-1]->key_length() !=
1224
primary_key=MAX_KEY; // Can't be used
1048
for (uint32_t i= 0 ; i < keyinfo->key_parts ; key_part++,i++)
1230
for (uint32_t i=0 ; i < keyinfo->key_parts ; key_part++,i++)
1051
if (! key_part->fieldnr)
1233
if (!key_part->fieldnr)
1053
abort(); // goto err;
1235
// error= 4; // Wrong file
1236
abort(); // goto err;
1055
1238
field= key_part->field= share->field[key_part->fieldnr-1];
1056
1239
key_part->type= field->key_type();
1271
1458
error= parse_table_proto(session, table, share);
1273
share->table_category= TABLE_CATEGORY_USER;
1460
share->table_category= get_table_category(& share->db, & share->table_name);
1463
session->status_var.opened_shares++;
1276
1466
if (error && !error_given)
1278
1468
share->error= error;
1279
share->open_table_error(error, (share->open_errno= errno), 0);
1469
open_table_error(share, error, (share->open_errno= my_errno), 0);
1287
Open a table based on a TableShare
1476
Clear flag GET_FIXED_FIELDS_FLAG in all fields of the table.
1477
This routine is used for error handling purposes.
1481
table Table object for which virtual columns are set-up
1486
static void clear_field_flag(Table *table)
1490
for (ptr= table->field; *ptr; ptr++)
1491
(*ptr)->flags&= (~GET_FIXED_FIELDS_FLAG);
1495
The function uses the feature in fix_fields where the flag
1496
GET_FIXED_FIELDS_FLAG is set for all fields in the item tree.
1497
This field must always be reset before returning from the function
1498
since it is used for other purposes as well.
1501
fix_fields_vcol_func()
1502
session The thread object
1503
func_item The item tree reference of the virtual columnfunction
1504
table The table object
1505
field_name The name of the processed field
1508
true An error occurred, something was wrong with the
1510
false Ok, a partition field array was created
1513
bool fix_fields_vcol_func(Session *session,
1516
const char *field_name)
1518
uint32_t dir_length, home_dir_length;
1521
TableList *save_table_list, *save_first_table, *save_last_table;
1523
Name_resolution_context *context;
1524
const char *save_where;
1526
char db_name_string[FN_REFLEN];
1527
bool save_use_only_table_context;
1528
Field **ptr, *field;
1529
enum_mark_columns save_mark_used_columns= session->mark_used_columns;
1533
Set-up the TABLE_LIST object to be a list with a single table
1534
Set the object to zero to create NULL pointers and set alias
1535
and real name to table name and get database name from file name.
1538
bzero((void*)&tables, sizeof(TableList));
1539
tables.alias= tables.table_name= (char*) table->s->table_name.str;
1540
tables.table= table;
1541
tables.next_local= NULL;
1542
tables.next_name_resolution_table= NULL;
1543
memcpy(db_name_string,
1544
table->s->normalized_path.str,
1545
table->s->normalized_path.length);
1546
db_name_string[table->s->normalized_path.length]= '\0';
1547
dir_length= dirname_length(db_name_string);
1548
db_name_string[dir_length - 1]= 0;
1549
home_dir_length= dirname_length(db_name_string);
1550
db_name= &db_name_string[home_dir_length];
1553
session->mark_used_columns= MARK_COLUMNS_NONE;
1555
context= session->lex->current_context();
1556
table->map= 1; //To ensure correct calculation of const item
1557
table->get_fields_in_item_tree= true;
1558
save_table_list= context->table_list;
1559
save_first_table= context->first_name_resolution_table;
1560
save_last_table= context->last_name_resolution_table;
1561
context->table_list= &tables;
1562
context->first_name_resolution_table= &tables;
1563
context->last_name_resolution_table= NULL;
1564
func_expr->walk(&Item::change_context_processor, 0, (unsigned char*) context);
1565
save_where= session->where;
1566
session->where= "virtual column function";
1568
/* Save the context before fixing the fields*/
1569
save_use_only_table_context= session->lex->use_only_table_context;
1570
session->lex->use_only_table_context= true;
1571
/* Fix fields referenced to by the virtual column function */
1572
error= func_expr->fix_fields(session, (Item**)0);
1573
/* Restore the original context*/
1574
session->lex->use_only_table_context= save_use_only_table_context;
1575
context->table_list= save_table_list;
1576
context->first_name_resolution_table= save_first_table;
1577
context->last_name_resolution_table= save_last_table;
1579
if (unlikely(error))
1581
clear_field_flag(table);
1584
session->where= save_where;
1586
Walk through the Item tree checking if all items are valid
1587
to be part of the virtual column
1589
error= func_expr->walk(&Item::check_vcol_func_processor, 0, NULL);
1592
my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(0), field_name);
1593
clear_field_flag(table);
1596
if (unlikely(func_expr->const_item()))
1598
my_error(ER_CONST_EXPR_IN_VCOL, MYF(0));
1599
clear_field_flag(table);
1602
/* Ensure that this virtual column is not based on another virtual field. */
1604
while ((field= *(ptr++)))
1606
if ((field->flags & GET_FIXED_FIELDS_FLAG) &&
1609
my_error(ER_VCOL_BASED_ON_VCOL, MYF(0));
1610
clear_field_flag(table);
1615
Cleanup the fields marked with flag GET_FIXED_FIELDS_FLAG
1616
when calling fix_fields.
1618
clear_field_flag(table);
1622
table->get_fields_in_item_tree= false;
1623
session->mark_used_columns= save_mark_used_columns;
1624
table->map= 0; //Restore old value
1629
Unpack the definition of a virtual column
1632
unpack_vcol_info_from_frm()
1633
session Thread handler
1634
table Table with the checked field
1635
field Pointer to Field object
1636
open_mode Open table mode needed to determine
1637
which errors need to be generated in a failure
1638
error_reported updated flag for the caller that no other error
1639
messages are to be generated.
1645
bool unpack_vcol_info_from_frm(Session *session,
1648
LEX_STRING *vcol_expr,
1649
open_table_mode open_mode,
1650
bool *error_reported)
1655
Step 1: Construct a statement for the parser.
1656
The parsed string needs to take the following format:
1657
"PARSE_VCOL_EXPR (<expr_string_from_frm>)"
1659
char *vcol_expr_str;
1662
if (!(vcol_expr_str= (char*) alloc_root(&table->mem_root,
1664
parse_vcol_keyword.length + 3)))
1668
memcpy(vcol_expr_str,
1669
(char*) parse_vcol_keyword.str,
1670
parse_vcol_keyword.length);
1671
str_len= parse_vcol_keyword.length;
1672
memcpy(vcol_expr_str + str_len, "(", 1);
1674
memcpy(vcol_expr_str + str_len,
1675
(char*) vcol_expr->str,
1677
str_len+= vcol_expr->length;
1678
memcpy(vcol_expr_str + str_len, ")", 1);
1680
memcpy(vcol_expr_str + str_len, "\0", 1);
1682
Lex_input_stream lip(session, vcol_expr_str, str_len);
1685
Step 2: Setup session for parsing.
1686
1) make Item objects be created in the memory allocated for the Table
1687
object (not TABLE_SHARE)
1688
2) ensure that created Item's are not put on to session->free_list
1689
(which is associated with the parsed statement and hence cleared after
1691
3) setup a flag in the LEX structure to allow "PARSE_VCOL_EXPR"
1692
to be parsed as a SQL command.
1694
MEM_ROOT **root_ptr, *old_root;
1695
Item *backup_free_list= session->free_list;
1696
root_ptr= current_mem_root_ptr();
1697
old_root= *root_ptr;
1698
*root_ptr= &table->mem_root;
1699
session->free_list= NULL;
1700
session->lex->parse_vcol_expr= true;
1703
Step 3: Use the parser to build an Item object from.
1705
if (parse_sql(session, &lip))
1709
/* From now on use vcol_info generated by the parser. */
1710
field->vcol_info= session->lex->vcol_info;
1712
/* Validate the Item tree. */
1713
if (fix_fields_vcol_func(session,
1714
field->vcol_info->expr_item,
1718
if (open_mode == OTM_CREATE)
1721
During CREATE/ALTER TABLE it is ok to receive errors here.
1722
It is not ok if it happens during the opening of an frm
1723
file as part of a normal query.
1725
*error_reported= true;
1727
field->vcol_info= NULL;
1730
field->vcol_info->item_free_list= session->free_list;
1731
session->free_list= backup_free_list;
1732
*root_ptr= old_root;
1737
session->lex->parse_vcol_expr= false;
1738
session->free_items();
1739
*root_ptr= old_root;
1740
session->free_list= backup_free_list;
1746
Open a table based on a TABLE_SHARE
1290
1749
open_table_from_share()
1291
session Thread Cursor
1750
session Thread handler
1292
1751
share Table definition
1293
1752
alias Alias for table
1294
1753
db_stat open flags (for example HA_OPEN_KEYFILE|
1295
1754
HA_OPEN_RNDFILE..) can be 0 (example in
1296
1755
ha_example_table)
1756
prgflag READ_ALL etc..
1297
1757
ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
1298
1758
outparam result table
1759
open_mode One of OTM_OPEN|OTM_CREATE|OTM_ALTER
1760
if OTM_CREATE some errors are ignore
1761
if OTM_ALTER HA_OPEN is not called
1302
1765
1 Error (see open_table_error)
1303
1766
2 Error (see open_table_error)
1304
3 Wrong data in .frm cursor
1767
3 Wrong data in .frm file
1305
1768
4 Error (see open_table_error)
1306
1769
5 Error (see open_table_error: charset unavailable)
1307
1770
7 Table definition has changed in engine
1310
int open_table_from_share(Session *session, TableShare *share, const char *alias,
1311
uint32_t db_stat, uint32_t ha_open_flags,
1773
int open_table_from_share(Session *session, TABLE_SHARE *share, const char *alias,
1774
uint32_t db_stat, uint32_t prgflag, uint32_t ha_open_flags,
1775
Table *outparam, open_table_mode open_mode)
1315
uint32_t records, i, bitmap_size;
1778
uint32_t records, i;
1316
1779
bool error_reported= false;
1317
unsigned char *record, *bitmaps;
1780
unsigned char *record;
1781
Field **field_ptr, **vfield_ptr;
1320
1783
/* Parsing of partitioning information from .frm needs session->lex set up. */
1321
1784
assert(session->lex->is_lex_started);
1324
outparam->resetTable(session, share, db_stat);
1327
if (not (outparam->alias= strdup(alias)))
1330
/* Allocate Cursor */
1331
if (not (outparam->cursor= share->db_type()->getCursor(*share, &outparam->mem_root)))
1787
memset(outparam, 0, sizeof(*outparam));
1788
outparam->in_use= session;
1790
outparam->db_stat= db_stat;
1791
outparam->write_row_record= NULL;
1793
init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
1795
if (!(outparam->alias= strdup(alias)))
1797
outparam->quick_keys.init();
1798
outparam->covering_keys.init();
1799
outparam->keys_in_use_for_query.init();
1801
/* Allocate handler */
1803
if (!(prgflag & OPEN_FRM_FILE_ONLY))
1805
if (!(outparam->file= get_new_handler(share, &outparam->mem_root,
1336
if ((db_stat & HA_OPEN_KEYFILE))
1815
outparam->reginfo.lock_type= TL_UNLOCK;
1816
outparam->current_lock= F_UNLCK;
1818
if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
1820
if (prgflag & (READ_ALL+EXTRA_RECORD))
1341
1823
if (!(record= (unsigned char*) alloc_root(&outparam->mem_root,
1342
1824
share->rec_buff_length * records)))
1825
goto err; /* purecov: inspected */
1345
1827
if (records == 0)
1660
/* error message when opening a form cursor */
1662
void TableShare::open_table_error(int pass_error, int db_errno, int pass_errarg)
2094
/* Find where a form starts */
2095
/* if formname is NULL then only formnames is read */
2097
ulong get_form_pos(File file, unsigned char *head, TYPELIB *save_names)
2099
uint32_t a_length,names,length;
2100
unsigned char *pos,*buf;
2103
names=uint2korr(head+8);
2104
a_length=(names+2)*sizeof(char *); /* Room for two extra */
2109
save_names->type_names=0; /* Clear if error */
2113
length=uint2korr(head+4);
2114
lseek(file,64,SEEK_SET);
2115
if (!(buf= (unsigned char*) malloc(length+a_length+names*4)) ||
2116
my_read(file, buf+a_length, (size_t) (length+names*4),
2118
{ /* purecov: inspected */
2121
return(0L); /* purecov: inspected */
2123
pos= buf+a_length+length;
2124
ret_value=uint4korr(pos);
2129
free((unsigned char*) buf);
2132
memset(save_names, 0, sizeof(save_names));
2136
str=(char *) (buf+a_length);
2137
fix_type_pointers((const char ***) &buf,save_names,1,&str);
2144
Read string from a file with malloc
2147
We add an \0 at end of the read string to make reading of C strings easier
2150
int read_string(File file, unsigned char**to, size_t length)
2155
if (!(*to= (unsigned char*) malloc(length+1)) ||
2156
my_read(file, *to, length,MYF(MY_NABP)))
2161
return(1); /* purecov: inspected */
2163
*((char*) *to+length)= '\0';
2168
/* Add a new form to a form file */
2170
off_t make_new_entry(File file, unsigned char *fileinfo, TYPELIB *formnames,
2171
const char *newname)
2173
uint32_t i,bufflength,maxlength,n_length,length,names;
2174
off_t endpos,newpos;
2175
unsigned char buff[IO_SIZE];
2178
length=(uint32_t) strlen(newname)+1;
2179
n_length=uint2korr(fileinfo+4);
2180
maxlength=uint2korr(fileinfo+6);
2181
names=uint2korr(fileinfo+8);
2182
newpos=uint4korr(fileinfo+10);
2184
if (64+length+n_length+(names+1)*4 > maxlength)
2187
int4store(fileinfo+10,newpos);
2188
endpos= lseek(file,0,SEEK_END);/* Copy from file-end */
2189
bufflength= (uint32_t) (endpos & (IO_SIZE-1)); /* IO_SIZE is a power of 2 */
2191
while (endpos > maxlength)
2193
lseek(file,(off_t) (endpos-bufflength),SEEK_SET);
2194
if (my_read(file, buff, bufflength, MYF(MY_NABP+MY_WME)))
2196
lseek(file,(off_t) (endpos-bufflength+IO_SIZE),SEEK_SET);
2197
if ((my_write(file, buff,bufflength,MYF(MY_NABP+MY_WME))))
2199
endpos-=bufflength; bufflength=IO_SIZE;
2201
memset(buff, 0, IO_SIZE); /* Null new block */
2202
lseek(file,(ulong) maxlength,SEEK_SET);
2203
if (my_write(file,buff,bufflength,MYF(MY_NABP+MY_WME)))
2205
maxlength+=IO_SIZE; /* Fix old ref */
2206
int2store(fileinfo+6,maxlength);
2207
for (i=names, pos= (unsigned char*) *formnames->type_names+n_length-1; i--;
2210
endpos=uint4korr(pos)+IO_SIZE;
2211
int4store(pos,endpos);
2218
sprintf((char*)buff,"/%s/",newname);
2221
sprintf((char*)buff,"%s/",newname); /* purecov: inspected */
2222
lseek(file, 63 + n_length,SEEK_SET);
2223
if (my_write(file, buff, (size_t) length+1,MYF(MY_NABP+MY_WME)) ||
2224
(names && my_write(file,(unsigned char*) (*formnames->type_names+n_length-1),
2225
names*4, MYF(MY_NABP+MY_WME))) ||
2226
my_write(file, fileinfo+10, 4,MYF(MY_NABP+MY_WME)))
2227
return(0L); /* purecov: inspected */
2229
int2store(fileinfo+8,names+1);
2230
int2store(fileinfo+4,n_length+length);
2231
assert(ftruncate(file, newpos)==0);/* Append file with '\0' */
2233
} /* make_new_entry */
2236
/* error message when opening a form file */
2238
void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg)
1665
2241
char buff[FN_REFLEN];
1666
2242
myf errortype= ME_ERROR+ME_WAITTANG;
1668
switch (pass_error) {
1671
2247
if (db_errno == ENOENT)
1672
my_error(ER_NO_SUCH_TABLE, MYF(0), db.str, table_name.str);
2248
my_error(ER_NO_SUCH_TABLE, MYF(0), share->db.str, share->table_name.str);
1675
snprintf(buff, sizeof(buff), "%s",normalized_path.str);
2251
sprintf(buff,"%s",share->normalized_path.str);
1676
2252
my_error((db_errno == EMFILE) ? ER_CANT_OPEN_FILE : ER_FILE_NOT_FOUND,
1677
2253
errortype, buff, db_errno);
1683
2259
const char *datext= "";
1685
if (db_type() != NULL)
2261
if (share->db_type() != NULL)
1687
if ((cursor= db_type()->getCursor(*this, current_session->mem_root)))
2263
if ((file= get_new_handler(share, current_session->mem_root,
1689
if (!(datext= *db_type()->bas_ext()))
2266
if (!(datext= *file->bas_ext()))
1693
2270
err_no= (db_errno == ENOENT) ? ER_FILE_NOT_FOUND : (db_errno == EAGAIN) ?
1694
2271
ER_FILE_USED : ER_CANT_OPEN_FILE;
1695
snprintf(buff, sizeof(buff), "%s%s", normalized_path.str,datext);
2272
sprintf(buff,"%s%s", share->normalized_path.str,datext);
1696
2273
my_error(err_no,errortype, buff, db_errno);
1702
const char *csname= get_charset_name((uint32_t) pass_errarg);
2279
const char *csname= get_charset_name((uint32_t) errarg);
1704
2281
if (!csname || csname[0] =='?')
1706
snprintf(tmp, sizeof(tmp), "#%d", pass_errarg);
2283
snprintf(tmp, sizeof(tmp), "#%d", errarg);
1709
2286
my_printf_error(ER_UNKNOWN_COLLATION,
1710
2287
_("Unknown collation '%s' in table '%-.64s' definition"),
1711
MYF(0), csname, table_name.str);
2288
MYF(0), csname, share->table_name.str);
1715
snprintf(buff, sizeof(buff), "%s", normalized_path.str);
2292
sprintf(buff,"%s",share->normalized_path.str);
1716
2293
my_printf_error(ER_NOT_FORM_FILE,
1717
2294
_("Table '%-.64s' was created with a different version "
1718
2295
"of Drizzle and cannot be read"),
2687
Checks whether a table is intact. Should be done *just* after the table has
2690
@param[in] table The table to check
2691
@param[in] table_f_count Expected number of columns in the table
2692
@param[in] table_def Expected structure of the table (column name
2696
@retval TRUE There was an error. An error message is output
2697
to the error log. We do not push an error
2698
message into the error stack because this
2699
function is currently only called at start up,
2700
and such errors never reach the user.
2704
Table::table_check_intact(const uint32_t table_f_count,
2705
const TABLE_FIELD_W_TYPE *table_def)
2709
bool fields_diff_count;
2711
fields_diff_count= (s->fields != table_f_count);
2712
if (fields_diff_count)
2715
/* previous MySQL version */
2716
if (DRIZZLE_VERSION_ID > s->mysql_version)
2718
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE),
2719
alias, table_f_count, s->fields,
2720
s->mysql_version, DRIZZLE_VERSION_ID);
2723
else if (DRIZZLE_VERSION_ID == s->mysql_version)
2725
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED), alias,
2726
table_f_count, s->fields);
2730
Something has definitely changed, but we're running an older
2731
version of MySQL with new system tables.
2732
Let's check column definitions. If a column was added at
2733
the end of the table, then we don't care much since such change
2734
is backward compatible.
2737
char buffer[STRING_BUFFER_USUAL_SIZE];
2738
for (i=0 ; i < table_f_count; i++, table_def++)
2740
String sql_type(buffer, sizeof(buffer), system_charset_info);
2744
Field *cur_field= this->field[i];
2746
if (strncmp(cur_field->field_name, table_def->name.str,
2747
table_def->name.length))
2750
Name changes are not fatal, we use ordinal numbers to access columns.
2751
Still this can be a sign of a tampered table, output an error
2754
errmsg_printf(ERRMSG_LVL_ERROR, _("Incorrect definition of table %s.%s: "
2755
"expected column '%s' at position %d, found '%s'."),
2756
s->db.str, alias, table_def->name.str, i,
2757
cur_field->field_name);
2759
cur_field->sql_type(sql_type);
2761
Generally, if column types don't match, then something is
2764
However, we only compare column definitions up to the
2765
length of the original definition, since we consider the
2766
following definitions compatible:
2768
1. DATETIME and DATETIM
2769
2. INT(11) and INT(11
2770
3. SET('one', 'two') and SET('one', 'two', 'more')
2772
For SETs or ENUMs, if the same prefix is there it's OK to
2773
add more elements - they will get higher ordinal numbers and
2774
the new table definition is backward compatible with the
2777
if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
2778
table_def->type.length - 1))
2780
errmsg_printf(ERRMSG_LVL_ERROR,
2781
_("Incorrect definition of table %s.%s: "
2782
"expected column '%s' at position %d to have type "
2783
"%s, found type %s."),
2785
table_def->name.str, i, table_def->type.str,
2786
sql_type.c_ptr_safe());
2789
else if (table_def->cset.str && !cur_field->has_charset())
2791
errmsg_printf(ERRMSG_LVL_ERROR,
2792
_("Incorrect definition of table %s.%s: "
2793
"expected the type of column '%s' at position %d "
2794
"to have character set '%s' but the type has no "
2797
table_def->name.str, i, table_def->cset.str);
2800
else if (table_def->cset.str &&
2801
strcmp(cur_field->charset()->csname, table_def->cset.str))
2803
errmsg_printf(ERRMSG_LVL_ERROR,
2804
_("Incorrect definition of table %s.%s: "
2805
"expected the type of column '%s' at position %d "
2806
"to have character set '%s' but found "
2807
"character set '%s'."),
2809
table_def->name.str, i, table_def->cset.str,
2810
cur_field->charset()->csname);
2816
errmsg_printf(ERRMSG_LVL_ERROR,
2817
_("Incorrect definition of table %s.%s: "
2818
"expected column '%s' at position %d to have type %s "
2819
" but the column is not found."),
2821
table_def->name.str, i, table_def->type.str);
2830
Create Item_field for each column in the table.
2833
Table::fill_item_list()
2834
item_list a pointer to an empty list used to store items
2837
Create Item_field object for each column in the table and
2838
initialize it with the corresponding Field. New items are
2839
created in the current Session memory root.
2846
bool Table::fill_item_list(List<Item> *item_list) const
2849
All Item_field's created using a direct pointer to a field
2850
are fixed in Item_field constructor.
2852
for (Field **ptr= field; *ptr; ptr++)
2854
Item_field *item= new Item_field(*ptr);
2855
if (!item || item_list->push_back(item))
2862
Reset an existing list of Item_field items to point to the
2863
Fields of this table.
2866
Table::fill_item_list()
2867
item_list a non-empty list with Item_fields
2870
This is a counterpart of fill_item_list used to redirect
2871
Item_fields to the fields of a newly created table.
2872
The caller must ensure that number of items in the item_list
2873
is the same as the number of columns in the table.
2876
void Table::reset_item_list(List<Item> *item_list) const
2878
List_iterator_fast<Item> it(*item_list);
2879
for (Field **ptr= field; *ptr; ptr++)
2881
Item_field *item_field= (Item_field*) it++;
2882
assert(item_field != 0);
2883
item_field->reset_field(*ptr);
2889
Find underlying base tables (TableList) which represent given
2890
table_to_find (Table)
2893
TableList::find_underlying_table()
2894
table_to_find table to find
2897
0 table is not found
2898
found table reference
2901
TableList *TableList::find_underlying_table(Table *table_to_find)
2903
/* is this real table and table which we are looking for? */
2904
if (table == table_to_find && merge_underlying_list == 0)
2907
for (TableList *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
2910
if ((result= tbl->find_underlying_table(table_to_find)))
2917
cleunup items belonged to view fields translation table
2920
TableList::cleanup_items()
2923
void TableList::cleanup_items()
2928
bool TableList::placeholder()
2930
return derived || schema_table || (create && !table->getDBStat()) || !table;
2935
Set insert_values buffer
2939
mem_root memory pool for allocating
2943
TRUE - out of memory
2946
bool TableList::set_insert_values(MEM_ROOT *mem_root)
2950
if (!table->insert_values &&
2951
!(table->insert_values= (unsigned char *)alloc_root(mem_root,
2952
table->s->rec_buff_length)))
2961
Test if this is a leaf with respect to name resolution.
2964
TableList::is_leaf_for_name_resolution()
2967
A table reference is a leaf with respect to name resolution if
2968
it is either a leaf node in a nested join tree (table, view,
2969
schema table, subquery), or an inner node that represents a
2970
NATURAL/USING join, or a nested join with materialized join
2974
TRUE if a leaf, false otherwise.
2976
bool TableList::is_leaf_for_name_resolution()
2978
return (is_natural_join || is_join_columns_complete || !nested_join);
2983
Retrieve the first (left-most) leaf in a nested join tree with
2984
respect to name resolution.
2987
TableList::first_leaf_for_name_resolution()
2990
Given that 'this' is a nested table reference, recursively walk
2991
down the left-most children of 'this' until we reach a leaf
2992
table reference with respect to name resolution.
2995
The left-most child of a nested table reference is the last element
2996
in the list of children because the children are inserted in
3000
If 'this' is a nested table reference - the left-most child of
3001
the tree rooted in 'this',
3005
TableList *TableList::first_leaf_for_name_resolution()
3007
TableList *cur_table_ref= NULL;
3008
nested_join_st *cur_nested_join;
3010
if (is_leaf_for_name_resolution())
3012
assert(nested_join);
3014
for (cur_nested_join= nested_join;
3016
cur_nested_join= cur_table_ref->nested_join)
3018
List_iterator_fast<TableList> it(cur_nested_join->join_list);
3019
cur_table_ref= it++;
3021
If the current nested join is a RIGHT JOIN, the operands in
3022
'join_list' are in reverse order, thus the first operand is
3023
already at the front of the list. Otherwise the first operand
3024
is in the end of the list of join operands.
3026
if (!(cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
3029
while ((next= it++))
3030
cur_table_ref= next;
3032
if (cur_table_ref->is_leaf_for_name_resolution())
3035
return cur_table_ref;
3040
Retrieve the last (right-most) leaf in a nested join tree with
3041
respect to name resolution.
3044
TableList::last_leaf_for_name_resolution()
3047
Given that 'this' is a nested table reference, recursively walk
3048
down the right-most children of 'this' until we reach a leaf
3049
table reference with respect to name resolution.
3052
The right-most child of a nested table reference is the first
3053
element in the list of children because the children are inserted
3057
- If 'this' is a nested table reference - the right-most child of
3058
the tree rooted in 'this',
3062
TableList *TableList::last_leaf_for_name_resolution()
3064
TableList *cur_table_ref= this;
3065
nested_join_st *cur_nested_join;
3067
if (is_leaf_for_name_resolution())
3069
assert(nested_join);
3071
for (cur_nested_join= nested_join;
3073
cur_nested_join= cur_table_ref->nested_join)
3075
cur_table_ref= cur_nested_join->join_list.head();
3077
If the current nested is a RIGHT JOIN, the operands in
3078
'join_list' are in reverse order, thus the last operand is in the
3081
if ((cur_table_ref->outer_join & JOIN_TYPE_RIGHT))
3083
List_iterator_fast<TableList> it(cur_nested_join->join_list);
3085
cur_table_ref= it++;
3086
while ((next= it++))
3087
cur_table_ref= next;
3089
if (cur_table_ref->is_leaf_for_name_resolution())
3092
return cur_table_ref;
1992
3096
/*****************************************************************************
1993
3097
Functions to handle column usage bitmaps (read_set, write_set etc...)
1994
3098
*****************************************************************************/
2225
3337
if (found_next_number_field)
2226
3338
mark_auto_increment_column();
3339
/* Mark all virtual columns as writable */
3340
mark_virtual_columns();
3344
@brief Update the write and read table bitmap to allow
3345
using procedure save_in_field for all virtual columns
3351
Each virtual field is set in the write column map.
3352
All fields that the virtual columns are based on are set in the
3356
void Table::mark_virtual_columns(void)
3358
Field **vfield_ptr, *tmp_vfield;
3359
bool bitmap_updated= false;
3361
for (vfield_ptr= vfield; *vfield_ptr; vfield_ptr++)
3363
tmp_vfield= *vfield_ptr;
3364
assert(tmp_vfield->vcol_info && tmp_vfield->vcol_info->expr_item);
3365
tmp_vfield->vcol_info->expr_item->walk(&Item::register_field_in_read_map,
3366
1, (unsigned char *) 0);
3367
read_set->set(tmp_vfield->field_index);
3368
write_set->set(tmp_vfield->field_index);
3369
bitmap_updated= true;
3372
file->column_bitmaps_signal();
3377
Cleanup this table for re-execution.
3380
TableList::reinit_before_use()
3383
void TableList::reinit_before_use(Session *session)
3386
Reset old pointers to TABLEs: they are not valid since the tables
3387
were closed in the end of previous prepare or execute call.
3390
/* Reset is_schema_table_processed value(needed for I_S tables */
3391
schema_table_state= NOT_PROCESSED;
3393
TableList *embedded; /* The table at the current level of nesting. */
3394
TableList *parent_embedding= this; /* The parent nested table reference. */
3397
embedded= parent_embedding;
3398
if (embedded->prep_on_expr)
3399
embedded->on_expr= embedded->prep_on_expr->copy_andor_structure(session);
3400
parent_embedding= embedded->embedding;
3402
while (parent_embedding &&
3403
parent_embedding->nested_join->join_list.head() == embedded);
3407
Return subselect that contains the FROM list this table is taken from
3410
TableList::containing_subselect()
3413
Subselect item for the subquery that contains the FROM list
3414
this table is taken from if there is any
3419
Item_subselect *TableList::containing_subselect()
3421
return (select_lex ? select_lex->master_unit()->item : 0);
3425
Compiles the tagged hints list and fills up the bitmasks.
3428
process_index_hints()
3429
table the Table to operate on.
3432
The parser collects the index hints for each table in a "tagged list"
3433
(TableList::index_hints). Using the information in this tagged list
3434
this function sets the members Table::keys_in_use_for_query,
3435
Table::keys_in_use_for_group_by, Table::keys_in_use_for_order_by,
3436
Table::force_index and Table::covering_keys.
3438
Current implementation of the runtime does not allow mixing FORCE INDEX
3439
and USE INDEX, so this is checked here. Then the FORCE INDEX list
3440
(if non-empty) is appended to the USE INDEX list and a flag is set.
3442
Multiple hints of the same kind are processed so that each clause
3443
is applied to what is computed in the previous clause.
3445
USE INDEX (i1) USE INDEX (i2)
3448
and means "consider only i1 and i2".
3451
USE INDEX () USE INDEX (i1)
3454
and means "consider only the index i1"
3456
It is OK to have the same index several times, e.g. "USE INDEX (i1,i1)" is
3459
Different kind of hints (USE/FORCE/IGNORE) are processed in the following
3461
1. All indexes in USE (or FORCE) INDEX are added to the mask.
3464
e.g. "USE INDEX i1, IGNORE INDEX i1, USE INDEX i1" will not use i1 at all
3465
as if we had "USE INDEX i1, USE INDEX i1, IGNORE INDEX i1".
3467
As an optimization if there is a covering index, and we have
3468
IGNORE INDEX FOR GROUP/order_st, and this index is used for the JOIN part,
3469
then we have to ignore the IGNORE INDEX FROM GROUP/order_st.
3472
false no errors found
3473
TRUE found and reported an error.
3475
bool TableList::process_index_hints(Table *tbl)
3477
/* initialize the result variables */
3478
tbl->keys_in_use_for_query= tbl->keys_in_use_for_group_by=
3479
tbl->keys_in_use_for_order_by= tbl->s->keys_in_use;
3481
/* index hint list processing */
3484
key_map index_join[INDEX_HINT_FORCE + 1];
3485
key_map index_order[INDEX_HINT_FORCE + 1];
3486
key_map index_group[INDEX_HINT_FORCE + 1];
3489
bool have_empty_use_join= false, have_empty_use_order= false,
3490
have_empty_use_group= false;
3491
List_iterator <Index_hint> iter(*index_hints);
3493
/* initialize temporary variables used to collect hints of each kind */
3494
for (type= INDEX_HINT_IGNORE; type <= INDEX_HINT_FORCE; type++)
3496
index_join[type].clear_all();
3497
index_order[type].clear_all();
3498
index_group[type].clear_all();
3501
/* iterate over the hints list */
3502
while ((hint= iter++))
3506
/* process empty USE INDEX () */
3507
if (hint->type == INDEX_HINT_USE && !hint->key_name.str)
3509
if (hint->clause & INDEX_HINT_MASK_JOIN)
3511
index_join[hint->type].clear_all();
3512
have_empty_use_join= true;
3514
if (hint->clause & INDEX_HINT_MASK_ORDER)
3516
index_order[hint->type].clear_all();
3517
have_empty_use_order= true;
3519
if (hint->clause & INDEX_HINT_MASK_GROUP)
3521
index_group[hint->type].clear_all();
3522
have_empty_use_group= true;
3528
Check if an index with the given name exists and get his offset in
3529
the keys bitmask for the table
3531
if (tbl->s->keynames.type_names == 0 ||
3532
(pos= find_type(&tbl->s->keynames, hint->key_name.str,
3533
hint->key_name.length, 1)) <= 0)
3535
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), hint->key_name.str, alias);
3541
/* add to the appropriate clause mask */
3542
if (hint->clause & INDEX_HINT_MASK_JOIN)
3543
index_join[hint->type].set_bit (pos);
3544
if (hint->clause & INDEX_HINT_MASK_ORDER)
3545
index_order[hint->type].set_bit (pos);
3546
if (hint->clause & INDEX_HINT_MASK_GROUP)
3547
index_group[hint->type].set_bit (pos);
3550
/* cannot mix USE INDEX and FORCE INDEX */
3551
if ((!index_join[INDEX_HINT_FORCE].is_clear_all() ||
3552
!index_order[INDEX_HINT_FORCE].is_clear_all() ||
3553
!index_group[INDEX_HINT_FORCE].is_clear_all()) &&
3554
(!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join ||
3555
!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order ||
3556
!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group))
3558
my_error(ER_WRONG_USAGE, MYF(0), index_hint_type_name[INDEX_HINT_USE],
3559
index_hint_type_name[INDEX_HINT_FORCE]);
3563
/* process FORCE INDEX as USE INDEX with a flag */
3564
if (!index_join[INDEX_HINT_FORCE].is_clear_all() ||
3565
!index_order[INDEX_HINT_FORCE].is_clear_all() ||
3566
!index_group[INDEX_HINT_FORCE].is_clear_all())
3568
tbl->force_index= true;
3569
index_join[INDEX_HINT_USE].merge(index_join[INDEX_HINT_FORCE]);
3570
index_order[INDEX_HINT_USE].merge(index_order[INDEX_HINT_FORCE]);
3571
index_group[INDEX_HINT_USE].merge(index_group[INDEX_HINT_FORCE]);
3574
/* apply USE INDEX */
3575
if (!index_join[INDEX_HINT_USE].is_clear_all() || have_empty_use_join)
3576
tbl->keys_in_use_for_query.intersect(index_join[INDEX_HINT_USE]);
3577
if (!index_order[INDEX_HINT_USE].is_clear_all() || have_empty_use_order)
3578
tbl->keys_in_use_for_order_by.intersect (index_order[INDEX_HINT_USE]);
3579
if (!index_group[INDEX_HINT_USE].is_clear_all() || have_empty_use_group)
3580
tbl->keys_in_use_for_group_by.intersect (index_group[INDEX_HINT_USE]);
3582
/* apply IGNORE INDEX */
3583
tbl->keys_in_use_for_query.subtract (index_join[INDEX_HINT_IGNORE]);
3584
tbl->keys_in_use_for_order_by.subtract (index_order[INDEX_HINT_IGNORE]);
3585
tbl->keys_in_use_for_group_by.subtract (index_group[INDEX_HINT_IGNORE]);
3588
/* make sure covering_keys don't include indexes disabled with a hint */
3589
tbl->covering_keys.intersect(tbl->keys_in_use_for_query);
2231
3594
size_t Table::max_row_length(const unsigned char *data)
2343
3739
#define AVG_STRING_LENGTH_TO_PACK_ROWS 64
2344
3740
#define RATIO_TO_PACK_ROWS 2
2346
static void make_internal_temporary_table_path(Session *session, char *path)
2348
snprintf(path, FN_REFLEN, "%s%lx_%"PRIx64"_%x", TMP_FILE_PREFIX, (unsigned long)current_pid,
2349
session->thread_id, session->tmp_table++);
2351
internal::fn_format(path, path, drizzle_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME);
2355
3743
create_tmp_table(Session *session,Tmp_Table_Param *param,List<Item> &fields,
2356
3744
order_st *group, bool distinct, bool save_sum_fields,
2357
3745
uint64_t select_options, ha_rows rows_limit,
2358
const char *table_alias)
2360
memory::Root *mem_root_save, own_root;
3748
MEM_ROOT *mem_root_save, own_root;
2363
3751
uint i,field_count,null_count,null_pack_length;
2364
3752
uint32_t copy_func_count= param->func_count;
2365
3753
uint32_t hidden_null_count, hidden_null_pack_length, hidden_field_count;
2366
3754
uint32_t blob_count,group_null_items, string_count;
3755
uint32_t temp_pool_slot= MY_BIT_NONE;
2367
3756
uint32_t fieldnr= 0;
2368
3757
ulong reclength, string_total_length;
2369
bool using_unique_constraint= false;
2370
bool use_packed_rows= true;
3758
bool using_unique_constraint= 0;
3759
bool use_packed_rows= 0;
2371
3760
bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
2373
char path[FN_REFLEN];
3761
char *tmpname,path[FN_REFLEN];
2374
3762
unsigned char *pos, *group_buff, *bitmaps;
2375
3763
unsigned char *null_flags;
2376
3764
Field **reg_field, **from_field, **default_field;
2377
3765
uint32_t *blob_field;
2380
3768
KEY_PART_INFO *key_part_info;
2381
3769
Item **copy_func;
2382
3770
MI_COLUMNDEF *recinfo;
2383
3771
uint32_t total_uneven_bit_length= 0;
2384
3772
bool force_copy_fields= param->force_copy_fields;
2385
uint64_t max_rows= 0;
2387
3774
status_var_increment(session->status_var.created_tmp_tables);
2389
make_internal_temporary_table_path(session, path);
3776
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
3777
setNextBit(temp_pool);
3779
if (temp_pool_slot != MY_BIT_NONE) // we got a slot
3780
sprintf(path, "%s_%lx_%i", TMP_FILE_PREFIX,
3781
(unsigned long)current_pid, temp_pool_slot);
3784
/* if we run out of slots or we are not using tempool */
3785
sprintf(path,"%s%lx_%"PRIx64"_%x", TMP_FILE_PREFIX, (unsigned long)current_pid,
3786
session->thread_id, session->tmp_table++);
3790
No need to change table name to lower case as we are only creating
3791
MyISAM or HEAP tables here
3793
fn_format(path, path, drizzle_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME);
2393
if (! param->quick_group)
2394
group= 0; // Can't use group key
3798
if (!param->quick_group)
3799
group=0; // Can't use group key
2395
3800
else for (order_st *tmp=group ; tmp ; tmp=tmp->next)
3350
4770
if (new_table.open_tmp_table())
3352
if (table->cursor->indexes_are_disabled())
3353
new_table.cursor->ha_disable_indexes(HA_KEY_SWITCH_ALL);
3354
table->cursor->ha_index_or_rnd_end();
3355
table->cursor->ha_rnd_init(1);
4772
if (table->file->indexes_are_disabled())
4773
new_table.file->ha_disable_indexes(HA_KEY_SWITCH_ALL);
4774
table->file->ha_index_or_rnd_end();
4775
table->file->ha_rnd_init(1);
3356
4776
if (table->no_rows)
3358
new_table.cursor->extra(HA_EXTRA_NO_ROWS);
4778
new_table.file->extra(HA_EXTRA_NO_ROWS);
3359
4779
new_table.no_rows=1;
3362
4782
/* HA_EXTRA_WRITE_CACHE can stay until close, no need to disable it */
3363
new_table.cursor->extra(HA_EXTRA_WRITE_CACHE);
4783
new_table.file->extra(HA_EXTRA_WRITE_CACHE);
3366
4786
copy all old rows from heap table to MyISAM table
3367
4787
This is the only code that uses record[1] to read/write but this
3368
4788
is safe as this is a temporary MyISAM table without timestamp/autoincrement.
3370
while (!table->cursor->rnd_next(new_table.record[1]))
4790
while (!table->file->rnd_next(new_table.record[1]))
3372
write_err= new_table.cursor->ha_write_row(new_table.record[1]);
4792
write_err= new_table.file->ha_write_row(new_table.record[1]);
3376
4796
/* copy row that filled HEAP table */
3377
if ((write_err=new_table.cursor->ha_write_row(table->record[0])))
4797
if ((write_err=new_table.file->ha_write_row(table->record[0])))
3379
if (new_table.cursor->is_fatal_error(write_err, HA_CHECK_DUP) ||
4799
if (new_table.file->is_fatal_error(write_err, HA_CHECK_DUP) ||
3380
4800
!ignore_last_dupp_key_error)
3384
4804
/* remove heap table and change to use myisam table */
3385
(void) table->cursor->ha_rnd_end();
3386
(void) table->cursor->close(); // This deletes the table !
3387
delete table->cursor;
3388
table->cursor= NULL;
4805
(void) table->file->ha_rnd_end();
4806
(void) table->file->close(); // This deletes the table !
3389
4809
new_table.s= table->s; // Keep old share
3390
4810
*table= new_table;
3391
4811
*table->s= share;
3393
table->cursor->change_table_ptr(table, table->s);
4813
table->file->change_table_ptr(table, table->s);
3394
4814
table->use_all_columns();
3395
4815
if (save_proc_info)
3475
4890
bool Table::compare_record()
3477
4892
if (s->blob_fields + s->varchar_fields == 0)
3478
return memcmp(this->record[0], this->record[1], (size_t) s->reclength);
4893
return cmp_record(this, record[1]);
3480
4894
/* Compare null bits */
3481
if (memcmp(null_flags, null_flags + s->rec_buff_length, s->null_bytes))
3482
return true; /* Diff in NULL value */
4895
if (memcmp(null_flags,
4896
null_flags + s->rec_buff_length,
4898
return true; // Diff in NULL value
3484
4899
/* Compare updated fields */
3485
4900
for (Field **ptr= field ; *ptr ; ptr++)
3487
if (isWriteSet((*ptr)->field_index) &&
4902
if (write_set->test((*ptr)->field_index) &&
3488
4903
(*ptr)->cmp_binary_offset(s->rec_buff_length))
3495
* Store a record from previous record into next
3498
void Table::storeRecord()
3500
memcpy(record[1], record[0], (size_t) s->reclength);
3504
* Store a record as an insert
3507
void Table::storeRecordAsInsert()
3509
memcpy(insert_values, record[0], (size_t) s->reclength);
3513
* Store a record with default values
3516
void Table::storeRecordAsDefault()
3518
memcpy(s->default_values, record[0], (size_t) s->reclength);
3522
* Restore a record from previous record into next
3525
void Table::restoreRecord()
3527
memcpy(record[0], record[1], (size_t) s->reclength);
3531
* Restore a record with default values
3534
void Table::restoreRecordAsDefault()
3536
memcpy(record[0], s->default_values, (size_t) s->reclength);
3543
void Table::emptyRecord()
3545
restoreRecordAsDefault();
3546
memset(null_flags, 255, s->null_bytes);
3560
insert_values(NULL),
3562
next_number_field(NULL),
3563
found_next_number_field(NULL),
3564
timestamp_field(NULL),
3565
pos_in_table_list(NULL),
3574
derived_select_number(0),
3575
current_lock(F_UNLCK),
3585
open_placeholder(false),
3586
locked_by_name(false),
3588
auto_increment_field_not_null(false),
3589
alias_name_used(false),
3591
quick_condition_rows(0),
3592
timestamp_field_type(TIMESTAMP_NO_AUTO_SET),
3595
record[0]= (unsigned char *) 0;
3596
record[1]= (unsigned char *) 0;
3598
covering_keys.reset();
3603
keys_in_use_for_query.reset();
3604
keys_in_use_for_group_by.reset();
3605
keys_in_use_for_order_by.reset();
3607
memset(quick_rows, 0, sizeof(ha_rows) * MAX_KEY);
3608
memset(const_key_parts, 0, sizeof(ha_rows) * MAX_KEY);
3610
memset(quick_key_parts, 0, sizeof(unsigned int) * MAX_KEY);
3611
memset(quick_n_ranges, 0, sizeof(unsigned int) * MAX_KEY);
3613
memory::init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
3614
memset(&sort, 0, sizeof(filesort_info_st));
3617
4913
/*****************************************************************************
3618
4914
The different ways to read a record
3619
4915
Returns -1 if row was not found, 0 if row was found and 1 on errors
3620
4916
*****************************************************************************/
3622
/** Help function when we get some an error from the table Cursor. */
4918
/** Help function when we get some an error from the table handler. */
3624
4920
int Table::report_error(int error)