1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
#include "xt_config.h"
34
#include <drizzled/session.h>
35
#include <drizzled/table.h>
36
#include <drizzled/current_session.h>
40
#include "systab_xt.h"
41
#include "discover_xt.h"
43
#include "strutil_xt.h"
44
#include "database_xt.h"
47
#if MYSQL_VERSION_ID >= 50120
52
* -------------------------------------------------------------------------
53
* SYSTEM TABLE DEFINITIONS
56
//--------------------------------
57
static DT_FIELD_INFO xt_location_info[] =
59
{ "Path", 128, NULL, MYSQL_TYPE_VARCHAR, (CHARSET_INFO *) system_charset_info, 0, "The location of PBXT tables"},
60
{ "Table_count", 0, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The number of PBXT table in this location"},
61
{ NULL, 0, NULL, MYSQL_TYPE_STRING, NULL, 0, NULL}
64
static DT_FIELD_INFO xt_statistics_info[] =
66
{ "ID", 0, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The ID of the statistic"},
67
{ "Name", 40, NULL, MYSQL_TYPE_VARCHAR, (CHARSET_INFO *) system_charset_info, 0, "The name of the statistic"},
68
{ "Value", 0, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The accumulated value"},
69
{ NULL, 0, NULL, MYSQL_TYPE_STRING, NULL, 0, NULL}
73
static DT_FIELD_INFO xt_reference_info[] =
75
{"Table_name", 128, NULL, MYSQL_TYPE_STRING, system_charset_info, NOT_NULL_FLAG, "The name of the referencing table"},
76
{"Blob_id", NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The BLOB reference number - part of the BLOB URL"},
77
{"Column_name", 50, NULL, MYSQL_TYPE_STRING, system_charset_info, NOT_NULL_FLAG, "The column name of the referencing field"},
78
{"Row_condition", 50, NULL, MYSQL_TYPE_VARCHAR, system_charset_info, 0, "This condition identifies the row in the table"},
79
{"Blob_url", 50, NULL, MYSQL_TYPE_VARCHAR, system_charset_info, NOT_NULL_FLAG, "The BLOB URL for HTTP GET access"},
80
{"Repository_id", NULL, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The repository file number of the BLOB"},
81
{"Repo_blob_offset",NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The offset in the repository file"},
82
{"Blob_size", NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, NOT_NULL_FLAG, "The size of the BLOB in bytes"},
83
{"Deletion_time", NULL, NULL, MYSQL_TYPE_TIMESTAMP, NULL, 0, "The time the BLOB was deleted"},
84
{"Remove_in", NULL, NULL, MYSQL_TYPE_LONG, NULL, 0, "The number of seconds before the reference/BLOB is removed perminently"},
85
{"Temp_log_id", NULL, NULL, MYSQL_TYPE_LONG, NULL, 0, "Temporary log number of the referencing deletion entry"},
86
{"Temp_log_offset", NULL, NULL, MYSQL_TYPE_LONGLONG, NULL, 0, "Temporary log offset of the referencing deletion entry"},
87
{NULL, NULL, NULL, MYSQL_TYPE_STRING, NULL, 0, NULL}
91
#define XT_SYSTAB_INVALID 0
92
#define XT_SYSTAB_LOCATION_ID 1
93
#define XT_SYSTAB_STATISTICS_ID 2
95
static THR_LOCK sys_location_lock;
96
static THR_LOCK sys_statistics_lock;
97
static xtBool sys_lock_inited = FALSE;
99
static XTSystemTableShareRec xt_internal_tables[] =
101
{ XT_SYSTAB_LOCATION_ID, "pbxt.location", &sys_location_lock, xt_location_info, NULL, FALSE},
102
{ XT_SYSTAB_STATISTICS_ID, "pbxt.statistics", &sys_statistics_lock, xt_statistics_info, NULL, FALSE},
103
{ XT_SYSTAB_INVALID, NULL, NULL, NULL, NULL, FALSE}
108
static int pbms_discover_handler(handlerton *hton, THD* thd, const char *db, const char *name, uchar **frmblob, size_t *frmlen)
113
// Check that the database exists!
114
if ((!db) || ! my_stat(db,&stat_info,MYF(0)))
117
while (pbms_internal_tables[i].name) {
118
if (!strcasecmp(name, pbms_internal_tables[i].name)) {
119
err = ms_create_table_frm(hton, thd, db, name, pbms_internal_tables[i].info, pbms_internal_tables[i].keys, frmblob, frmlen);
130
* -------------------------------------------------------------------------
134
static void xt_my_set_notnull_in_record(Field *field, char *record)
137
record[(uint) (field->null_ptr - (uchar *) field->table->record[0])] &= (uchar) ~field->null_bit;
141
* -------------------------------------------------------------------------
145
XTOpenSystemTable::XTOpenSystemTable(XTThreadPtr self, XTDatabaseHPtr db, XTSystemTableShare *share, TABLE *table):
149
ost_my_table = table;
151
xt_heap_reference(self, db);
154
XTOpenSystemTable::~XTOpenSystemTable()
156
XTSystemTableShare::releaseSystemTable(this);
160
* -------------------------------------------------------------------------
164
XTLocationTable::XTLocationTable(XTThreadPtr self, XTDatabaseHPtr db, XTSystemTableShare *share, TABLE *table):
165
XTOpenSystemTable(self, db, share, table)
169
XTLocationTable::~XTLocationTable()
174
bool XTLocationTable::use()
179
bool XTLocationTable::unuse()
185
bool XTLocationTable::seqScanInit()
191
bool XTLocationTable::seqScanNext(char *buf, bool *eof)
197
xt_ht_lock(NULL, ost_db->db_tables);
198
if (lt_index >= xt_sl_get_size(ost_db->db_table_paths)) {
203
loadRow(buf, lt_index);
207
xt_ht_unlock(NULL, ost_db->db_tables);
212
csWord4 creation_time;
221
MX_BITMAP *save_write_set;
223
last_access = CS_GET_DISK_4(blob->rb_last_access_4);
224
last_ref = CS_GET_DISK_4(blob->rb_last_ref_4);
225
creation_time = CS_GET_DISK_4(blob->rb_create_time_4);
226
cont_type = CS_GET_DISK_2(blob->rb_cont_type_2);
227
ref_size = CS_GET_DISK_1(blob->rb_ref_size_1);
228
head_size = CS_GET_DISK_2(blob->rb_head_size_2);
229
blob_size = CS_GET_DISK_6(blob->rb_blob_size_6);
230
access_code = CS_GET_DISK_4(blob->rb_auth_code_4);
232
/* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when
234
* But I want to use it! :(
236
save_write_set = table->write_set;
237
table->write_set = NULL;
239
memset(buf, 0xFF, table->s->null_bytes);
240
for (Field **field=table->field ; *field ; field++) {
243
save = curr_field->ptr;
244
#if MYSQL_VERSION_ID < 50114
245
curr_field->ptr = (byte *) buf + curr_field->offset();
247
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
249
switch (curr_field->field_name[0]) {
251
ASSERT(strcmp(curr_field->field_name, "Access_code") == 0);
252
curr_field->store(access_code, true);
253
xt_my_set_notnull_in_record(curr_field, buf);
256
switch (curr_field->field_name[6]) {
259
ASSERT(strcmp(curr_field->field_name, "Repository_id") == 0);
260
curr_field->store(iRepoFile->myRepo->getRepoID(), true);
261
xt_my_set_notnull_in_record(curr_field, buf);
264
// Repo_blob_offset BIGINT
265
ASSERT(strcmp(curr_field->field_name, "Repo_blob_offset") == 0);
266
curr_field->store(iRepoOffset, true);
267
xt_my_set_notnull_in_record(curr_field, buf);
272
switch (curr_field->field_name[5]) {
275
ASSERT(strcmp(curr_field->field_name, "Blob_size") == 0);
276
curr_field->store(blob_size, true);
277
xt_my_set_notnull_in_record(curr_field, buf);
280
// Blob_data LONGBLOB
281
ASSERT(strcmp(curr_field->field_name, "Blob_data") == 0);
282
if (blob_size <= 0xFFFFFFF) {
283
iBlobBuffer->setLength((u_int) blob_size);
284
len = iRepoFile->read(iBlobBuffer->getBuffer(0), iRepoOffset + head_size, (size_t) blob_size, 0);
285
((Field_blob *) curr_field)->set_ptr(len, (byte *) iBlobBuffer->getBuffer(0));
286
xt_my_set_notnull_in_record(curr_field, buf);
292
// Head_size SMALLINT UNSIGNED
293
ASSERT(strcmp(curr_field->field_name, "Head_size") == 0);
294
curr_field->store(head_size, true);
295
xt_my_set_notnull_in_record(curr_field, buf);
298
switch (curr_field->field_name[1]) {
300
// Creation_time TIMESTAMP
301
ASSERT(strcmp(curr_field->field_name, "Creation_time") == 0);
302
curr_field->store(ms_my_1970_to_mysql_time(creation_time), true);
303
xt_my_set_notnull_in_record(curr_field, buf);
306
// Content_type CHAR(128)
307
ASSERT(strcmp(curr_field->field_name, "Content_type") == 0);
308
CSString *cont_type_str = ost_share->mySysDatabase->getContentType(cont_type);
310
curr_field->store(cont_type_str->getCString(), cont_type_str->length(), &my_charset_utf8_general_ci);
311
cont_type_str->release();
312
xt_my_set_notnull_in_record(curr_field, buf);
318
switch (curr_field->field_name[5]) {
320
// Last_ref_time TIMESTAMP
321
ASSERT(strcmp(curr_field->field_name, "Last_ref_time") == 0);
322
curr_field->store(ms_my_1970_to_mysql_time(last_ref), true);
323
xt_my_set_notnull_in_record(curr_field, buf);
326
// Last_access_time TIMESTAMP
327
ASSERT(strcmp(curr_field->field_name, "Last_access_time") == 0);
328
curr_field->store(ms_my_1970_to_mysql_time(last_access), true);
329
xt_my_set_notnull_in_record(curr_field, buf);
334
curr_field->ptr = save;
337
table->write_set = save_write_set;
342
void XTLocationTable::loadRow(char *buf, xtWord4 row_id)
344
TABLE *table = ost_my_table;
346
XTTablePathPtr tp_ptr;
348
MX_BITMAP *save_write_set;
350
/* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when
352
* But I want to use it! :(
354
save_write_set = table->write_set;
355
table->write_set = NULL;
357
memset(buf, 0xFF, table->s->null_bytes);
359
tp_ptr = *((XTTablePathPtr *) xt_sl_item_at(ost_db->db_table_paths, row_id));
361
for (Field **field=table->field ; *field ; field++) {
364
save = curr_field->ptr;
365
#if MYSQL_VERSION_ID < 50114
366
curr_field->ptr = (byte *) buf + curr_field->offset();
368
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
370
switch (curr_field->field_name[0]) {
373
ASSERT_NS(strcmp(curr_field->field_name, "Path") == 0);
374
curr_field->store(tp_ptr->tp_path, strlen(tp_ptr->tp_path), &my_charset_utf8_general_ci);
375
xt_my_set_notnull_in_record(curr_field, buf);
379
ASSERT_NS(strcmp(curr_field->field_name, "Table_count") == 0);
380
curr_field->store(tp_ptr->tp_tab_count, true);
381
xt_my_set_notnull_in_record(curr_field, buf);
384
curr_field->ptr = save;
386
table->write_set = save_write_set;
389
xtWord4 XTLocationTable::seqScanPos(xtWord1 *XT_UNUSED(buf))
394
bool XTLocationTable::seqScanRead(xtWord4 rec_id, char *buf)
396
loadRow(buf, rec_id);
401
* -------------------------------------------------------------------------
405
XTStatisticsTable::XTStatisticsTable(XTThreadPtr self, XTDatabaseHPtr db, XTSystemTableShare *share, TABLE *table):
406
XTOpenSystemTable(self, db, share, table)
410
XTStatisticsTable::~XTStatisticsTable()
415
bool XTStatisticsTable::use()
420
bool XTStatisticsTable::unuse()
426
bool XTStatisticsTable::seqScanInit()
429
xt_gather_statistics(&tt_statistics);
433
bool XTStatisticsTable::seqScanNext(char *buf, bool *eof)
439
if (tt_index >= XT_STAT_CURRENT_MAX) {
444
loadRow(buf, tt_index);
451
void XTStatisticsTable::loadRow(char *buf, xtWord4 rec_id)
453
TABLE *table = ost_my_table;
454
MX_BITMAP *save_write_set;
457
const char *stat_name;
460
/* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when
462
* But I want to use it! :(
464
save_write_set = table->write_set;
465
table->write_set = NULL;
467
memset(buf, 0xFF, table->s->null_bytes);
469
stat_name = xt_get_stat_meta_data(rec_id)->sm_name;
470
stat_value = xt_get_statistic(&tt_statistics, ost_db, rec_id);
472
for (Field **field=table->field ; *field ; field++) {
475
save = curr_field->ptr;
476
#if MYSQL_VERSION_ID < 50114
477
curr_field->ptr = (byte *) buf + curr_field->offset();
479
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
481
switch (curr_field->field_name[0]) {
484
ASSERT_NS(strcmp(curr_field->field_name, "ID") == 0);
485
curr_field->store(rec_id+1, true);
486
xt_my_set_notnull_in_record(curr_field, buf);
490
ASSERT_NS(strcmp(curr_field->field_name, "Name") == 0);
491
curr_field->store(stat_name, strlen(stat_name), &my_charset_utf8_general_ci);
492
xt_my_set_notnull_in_record(curr_field, buf);
496
ASSERT_NS(strcmp(curr_field->field_name, "Value") == 0);
497
curr_field->store(stat_value, true);
498
xt_my_set_notnull_in_record(curr_field, buf);
501
curr_field->ptr = save;
503
table->write_set = save_write_set;
506
xtWord4 XTStatisticsTable::seqScanPos(xtWord1 *XT_UNUSED(buf))
511
bool XTStatisticsTable::seqScanRead(xtWord4 rec_id, char *buf)
513
loadRow(buf, rec_id);
518
* -------------------------------------------------------------------------
519
* SYSTEM TABLE SHARES
522
static void st_path_to_table_name(size_t size, char *buffer, const char *path)
526
xt_strcpy(size, buffer, xt_last_2_names_of_path(path));
527
xt_remove_extension(buffer);
528
if ((str = strchr(buffer, '\\')))
530
if ((str = strchr(buffer, '/')))
534
void XTSystemTableShare::startUp(XTThreadPtr XT_UNUSED(self))
536
thr_lock_init(&sys_location_lock);
537
thr_lock_init(&sys_statistics_lock);
538
sys_lock_inited = TRUE;
541
void XTSystemTableShare::shutDown(XTThreadPtr XT_UNUSED(self))
543
if (sys_lock_inited) {
544
thr_lock_delete(&sys_location_lock);
545
thr_lock_delete(&sys_statistics_lock);
546
sys_lock_inited = FALSE;
550
bool XTSystemTableShare::isSystemTable(const char *table_path)
555
st_path_to_table_name(100, tab_name, table_path);
556
while (xt_internal_tables[i].sts_path) {
557
if (strcasecmp(tab_name, xt_internal_tables[i].sts_path) == 0)
564
void XTSystemTableShare::setSystemTableDeleted(const char *table_path)
569
st_path_to_table_name(100, tab_name, table_path);
570
while (xt_internal_tables[i].sts_path) {
571
if (strcasecmp(tab_name, xt_internal_tables[i].sts_path) == 0) {
572
xt_internal_tables[i].sts_exists = FALSE;
579
bool XTSystemTableShare::doesSystemTableExist()
583
while (xt_internal_tables[i].sts_path) {
584
if (xt_internal_tables[i].sts_exists)
591
void XTSystemTableShare::createSystemTables(XTThreadPtr XT_UNUSED(self), XTDatabaseHPtr XT_UNUSED(db))
596
while (xt_internal_tables[i].sts_path) {
598
// must ignore errors here
599
drizzled::Session *session = current_thd;
600
//session->main_da.disable_status();
602
if (!xt_create_table_frm(pbxt_hton,
604
strchr(xt_internal_tables[i].sts_path, '.') + 1,
605
xt_internal_tables[i].sts_info,
606
xt_internal_tables[i].sts_keys,
607
TRUE /*do not recreate*/))
608
xt_internal_tables[i].sts_exists = TRUE;
611
session->main_da.reset_diagnostics_area();
617
XTOpenSystemTable *XTSystemTableShare::openSystemTable(XTThreadPtr self, const char *table_path, TABLE *table)
619
XTSystemTableShare *share;
620
XTOpenSystemTable *otab = NULL;
624
st_path_to_table_name(100, tab_name, table_path);
625
while (xt_internal_tables[i].sts_path) {
626
if (strcasecmp(tab_name, xt_internal_tables[i].sts_path) == 0) {
627
share = &xt_internal_tables[i];
635
share->sts_exists = TRUE;
636
switch (share->sts_id) {
637
case XT_SYSTAB_LOCATION_ID:
638
if (!(otab = new XTLocationTable(self, self->st_database, share, table)))
639
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
641
case XT_SYSTAB_STATISTICS_ID:
642
if (!(otab = new XTStatisticsTable(self, self->st_database, share, table)))
643
xt_throw_errno(XT_CONTEXT, XT_ENOMEM);
646
xt_throw_taberr(XT_CONTEXT, XT_ERR_TABLE_NOT_FOUND, (XTPathStrPtr) table_path);
653
void XTSystemTableShare::releaseSystemTable(XTOpenSystemTable *tab)
656
XTThreadPtr self = xt_get_self();
659
xt_heap_release(self, tab->ost_db);