1
/* Copyright (C) 2009 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
* System variables table.
26
#include <drizzled/common.h>
27
#include <drizzled/session.h>
28
#include <drizzled/sql_lex.h>
29
#include <drizzled/field/blob.h>
32
#include "cslib/CSConfig.h"
35
#include <sys/types.h>
40
//#include "mysql_priv.h"
41
#include "cslib/CSGlobal.h"
42
#include "cslib/CSStrUtil.h"
43
#include "cslib/CSLog.h"
49
#include "repository_ms.h"
50
#include "database_ms.h"
51
#include "compactor_ms.h"
52
#include "open_table_ms.h"
53
#include "discover_ms.h"
57
#include "systab_variable_ms.h"
59
#define MS_REPOSITORY_STORAGE_TYPE "REPOSITORY"
60
#define MS_CLOUD_STORAGE_TYPE "CLOUD"
62
DT_FIELD_INFO pbms_variable_info[]=
64
{"Id", NOVAL, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The variable ID"},
65
{"Name", 32, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "PBMS variable name"},
66
{"Value", 1024, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, 0, "PBMS variable value."},
67
{"Description", 124, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "PBMS variable description."},
68
{NULL,NOVAL, NULL, MYSQL_TYPE_STRING,NULL, 0, NULL}
71
DT_KEY_INFO pbms_variable_keys[]=
73
{"pbms_variable_pk", PRI_KEY_FLAG, {"Id", NULL}},
77
typedef const char *(*PBMSVarGetFunc)(MSDatabase *db, const char *dflt_value);
78
typedef const char *(*PBMSVarCheckFunc)(char *value, bool *ok);
79
typedef void (*PBMSVarActionFunc)(MSDatabase *db, const char *value);
82
bool hidden; // true if the value is not to be displayed
86
bool save; // true if the value is to be saved to disk on update
88
PBMSVarCheckFunc check;
89
PBMSVarActionFunc action;
90
} PBMSVariableRec, *PBMSVariablePtr;
92
CSLock MSVariableTable::gVarLock;
94
//---------------------------
95
static char *cleanupVariable(char *value, int *len)
99
while (*value && isspace(*value)) value++;
100
ptr = value + strlen(value) -1;
101
while ((ptr > value) && isspace(*ptr)) ptr--;
107
*ptr = toupper(*ptr);
115
//---------------------------
116
static const char *get_DumpRestore(MSDatabase *db, const char *)
121
if (db->isRecovering())
129
//---------------------------
130
static const char *readOnlyCheck(char *, bool *ok)
133
return "Value is Read Only.";
135
//---------------------------
136
static const char *boolCheck(char *value, bool *ok)
138
const char *val = "Invalid boolean variable, try 'true' or 'false'";
141
value = cleanupVariable(value, &len);
160
if (!strcmp(value, "TRUE")) {
167
if (!strcmp(value, "FALSE")) {
179
//---------------------------
180
static const char *storageTypeCheck(char *value, bool *ok)
182
const char *val = "Invalid storage type, try '"MS_REPOSITORY_STORAGE_TYPE"' or '"MS_CLOUD_STORAGE_TYPE"'";
185
value = cleanupVariable(value, &len);
188
if (!strcmp(value, MS_REPOSITORY_STORAGE_TYPE)) {
190
val = MS_REPOSITORY_STORAGE_TYPE;
191
} else if (!strcmp(value, MS_CLOUD_STORAGE_TYPE)) {
193
val = MS_CLOUD_STORAGE_TYPE;
199
//---------------------------
200
static void set_DumpRestore(MSDatabase *db, const char *value)
204
db->setRecovering((strcmp(value, "TRUE") == 0));
209
//---------------------------
210
static void set_StorageType(MSDatabase *db, const char *value)
215
if (!strcmp(value, MS_REPOSITORY_STORAGE_TYPE))
216
db->myBlobType = MS_STANDARD_STORAGE;
217
else if (!strcmp(value, MS_CLOUD_STORAGE_TYPE))
218
db->myBlobType = MS_CLOUD_STORAGE;
224
//---------------------------
225
static const char *get_StorageType(MSDatabase *db, const char *)
227
const char *value = "Unknown";
231
if (db->myBlobType == MS_STANDARD_STORAGE)
232
value = MS_REPOSITORY_STORAGE_TYPE;
233
else if (db->myBlobType == MS_CLOUD_STORAGE)
234
value = MS_CLOUD_STORAGE_TYPE;
240
//---------------------------
241
static const char *get_S3CloudRefNo(MSDatabase *db, const char *)
243
static char value[20];
248
num = db->myBlobCloud->cl_getDefaultCloudRef();
249
snprintf(value, 20, "%"PRIu32"", num);
255
//---------------------------
256
static void set_S3CloudRefNo(MSDatabase *db, const char *value)
261
db->myBlobCloud->cl_setDefaultCloudRef(atol(value));
267
//---------------------------
268
static void set_BackupNo(MSDatabase *db, const char *value)
273
db->myBlobCloud->cl_setRecoveryNumber(value);
279
//---------------------------
280
static const char *get_BackupNo(MSDatabase *db, const char *)
286
value = db->myBlobCloud->cl_getRecoveryNumber();
292
static PBMSVariableRec variables[] = {
293
{false, "Storage-Type", MS_REPOSITORY_STORAGE_TYPE, "How the BLOB data is to be stored.", true, get_StorageType, storageTypeCheck, set_StorageType},
294
{false, "S3-Cloud-Ref", NULL, "The S3 cloud reference id from the pbms.pbms_cloud table used for new BLOB storage.", true, get_S3CloudRefNo, NULL, set_S3CloudRefNo},
295
{false, RESTORE_DUMP_VAR, "FALSE", "Indicate if the database is being restored from a dump file.", false, get_DumpRestore, boolCheck, set_DumpRestore},
296
// Hidden variables should be placed at the end.
297
{true, BACKUP_NUMBER_VAR, NULL, "The backup number for cloud blob data after a drag and drop restore.", true, get_BackupNo, readOnlyCheck, set_BackupNo}
300
static const uint32_t num_variables = 4;
302
//---------------------------
303
//----------------------------
304
#define PBMS_VARIABLES_FILE "pbms_variables"
305
static CSPath *getSysVarFile(CSString *db_path)
313
path = CSPath::newPath(RETAIN(db_path), PBMS_VARIABLES_FILE".dat");
315
if (!path->exists()) {
318
tmp_path = CSPath::newPath(RETAIN(db_path), PBMS_VARIABLES_FILE".tmp");
320
if (tmp_path->exists())
321
tmp_path->rename(PBMS_VARIABLES_FILE".dat");
331
class LoadTableCleanUp : public CSRefObject {
339
LoadTableCleanUp(): CSRefObject(),
340
do_cleanup(false), myself(NULL){}
345
CSL.log(myself, CSLog::Protocol, "\nRestore failed!\n");
347
myself->logException();
351
void setCleanUp(CSThread *self)
364
void MSVariableTable::loadTable(MSDatabase *db)
371
path = getSysVarFile(RETAIN(db->myDatabasePath));
374
if (path->exists()) {
376
CSStringBuffer *string;
377
size_t size = 0, pos =0;
380
new_(string, CSStringBuffer(20));
383
file = path->openFile(CSFile::READONLY);
385
size = file->getEOF();
386
string->setLength(size);
387
file->read(string->getBuffer(0), 0, size, size);
391
name = string->getBuffer(pos);
392
pos += strlen(name) +1;
396
value = string->getBuffer(pos);
397
pos += strlen(value) +1;
401
for (uint32_t i =0; i < num_variables; i++) {
402
if (variables[i].save && variables[i].action && !strcmp(name, variables[i].name)) {
403
variables[i].action(RETAIN(db), value);
411
} else { // Set the default values
412
for (uint32_t i =0; i < num_variables; i++) {
413
if (variables[i].value && variables[i].action) {
414
variables[i].action(RETAIN(db), variables[i].value);
422
// Check to see if there is cloud storage and if the database is not
423
// currently recovering, then try to restore the BLOBs.
424
if ((db->myBlobType == MS_CLOUD_STORAGE) && db->myBlobCloud->cl_mustRecoverBlobs() && !db->isRecovering()) {
425
CSL.log(self, CSLog::Protocol, "Restoring Cloud BLOBs for database: ");
426
CSL.log(self, CSLog::Protocol, db->myDatabaseName->getCString());
427
CSL.log(self, CSLog::Protocol, " ...");
429
LoadTableCleanUp *cleanup;
431
new_(cleanup, LoadTableCleanUp());
433
cleanup->setCleanUp(self);
435
db->myBlobCloud->cl_restoreDB();
437
cleanup->cancelCleanUp();
440
CSL.log(self, CSLog::Protocol, "\nRestore done.\n");
442
set_BackupNo(RETAIN(db), "0");
443
saveTable(RETAIN(db));
451
void MSVariableTable::saveTable(MSDatabase *db)
457
size_t offset = 0, len;
462
path = CSPath::newPath(RETAIN(db->myDatabasePath), PBMS_VARIABLES_FILE".tmp");
464
file = path->openFile(CSFile::CREATE | CSFile::TRUNCATE);
467
for (uint32_t i = 0; i < num_variables; i++) {
468
if (! variables[i].save) continue;
470
len = strlen(variables[i].name)+1;
471
file->write(variables[i].name, offset, len);
474
value = variables[i].get(RETAIN(db), variables[i].value);
476
len = strlen(value)+1;
477
file->write(value, offset, len);
480
file->write(&null_char, offset, 1);
487
old_path = CSPath::newPath(RETAIN(db->myDatabasePath), PBMS_VARIABLES_FILE".dat");
489
if (old_path->exists())
491
path->rename(PBMS_VARIABLES_FILE".dat");
500
MSVariableTable::MSVariableTable(MSSystemTableShare *share, TABLE *table):
501
MSOpenSystemTable(share, table),
506
MSVariableTable::~MSVariableTable()
511
void MSVariableTable::use()
516
void MSVariableTable::unuse()
522
void MSVariableTable::seqScanInit()
527
bool MSVariableTable::seqScanNext(char *buf)
529
TABLE *table = mySQLTable;
532
MY_BITMAP *save_write_set;
538
if (iVariableIndex >= num_variables)
540
var = &(variables[iVariableIndex++]);
542
} while (var->hidden);
544
save_write_set = table->write_set;
545
table->write_set = NULL;
548
memset(buf, 0xFF, table->getNullBytes());
550
memset(buf, 0xFF, table->s->null_bytes);
552
for (Field **field=GET_TABLE_FIELDS(table) ; *field ; field++) {
554
save = curr_field->ptr;
555
#if MYSQL_VERSION_ID < 50114
556
curr_field->ptr = (byte *) buf + curr_field->offset();
559
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->getTable()->getInsertRecord());
561
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
564
switch (curr_field->field_name[0]) {
566
ASSERT(strcmp(curr_field->field_name, "Id") == 0);
567
curr_field->store(iVariableIndex, true);
568
setNotNullInRecord(curr_field, buf);
572
ASSERT(strcmp(curr_field->field_name, "Name") == 0);
573
curr_field->store(var->name, strlen(var->name), &UTF8_CHARSET);
574
setNotNullInRecord(curr_field, buf);
578
ASSERT(strcmp(curr_field->field_name, "Value") == 0);
580
value = var->get(RETAIN(myShare->mySysDatabase), var->value);
582
curr_field->store(value, strlen(value), &UTF8_CHARSET);
583
setNotNullInRecord(curr_field, buf);
589
ASSERT(strcmp(curr_field->field_name, "Description") == 0);
590
curr_field->store(var->info, strlen(var->info), &UTF8_CHARSET);
591
setNotNullInRecord(curr_field, buf);
595
curr_field->ptr = save;
598
table->write_set = save_write_set;
602
void MSVariableTable::seqScanPos(unsigned char *pos)
604
int32_t index = iVariableIndex -1;
606
index = 0; // This is probably an error condition.
608
mi_int4store(pos, index);
611
void MSVariableTable::seqScanRead(unsigned char *pos, char *buf)
613
iVariableIndex = mi_uint4korr(pos);
617
void MSVariableTable::updateRow(char *old_data, char *new_data)
620
String n_var_name, n_var_value;
622
const char *clean_value;
626
getFieldValue(old_data, 0, &o_id);
627
getFieldValue(old_data, 1, &o_var_name);
629
getFieldValue(new_data, 0, &n_id);
630
getFieldValue(new_data, 1, &n_var_name);
631
getFieldValue(new_data, 2, &n_var_value);
633
// The command names must match.
634
if ((n_id != o_id) || UTF8_CHARSET.strcasecmp(o_var_name.c_str(), n_var_name.c_str()))
635
CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only fields in the "VARIABLES_TABLE_NAME" table.");
638
if (n_id > num_variables) // Should never happen
639
CSException::throwException(CS_CONTEXT, HA_ERR_KEY_NOT_FOUND, "Invalid id");
641
CSStringBuffer *value;
642
new_(value, CSStringBuffer(0));
644
value->append(n_var_value.c_ptr(), n_var_value.length());
646
// check the input value converting it to a standard format where aplicable:
647
if (variables[n_id].check) {
649
clean_value = variables[n_id].check(value->getCString(), &ok);
651
CSException::throwException(CS_CONTEXT, HA_ERR_GENERIC, clean_value);
653
clean_value = value->getCString();
655
// Execute the action associated with the variable.
656
if (variables[n_id].action) {
657
variables[n_id].action(RETAIN(myShare->mySysDatabase), clean_value);
662
if (variables[n_id].save) {
663
saveTable(RETAIN(myShare->mySysDatabase));
669
void MSVariableTable::transferTable(MSDatabase *to_db, MSDatabase *from_db)
677
path = CSPath::newPath(RETAIN(from_db->myDatabasePath), PBMS_VARIABLES_FILE".dat");
679
if (path->exists()) {
681
bu_path = CSPath::newPath(RETAIN(to_db->myDatabasePath), PBMS_VARIABLES_FILE".dat");
682
path->copyTo(bu_path, true);
692
void MSVariableTable::setVariable(MSDatabase *db, const char *name, const char *value)
698
for (uint32_t i =0; db && i < num_variables; i++) {
699
if (variables[i].action && !strcmp(name, variables[i].name)) {
700
variables[i].action(RETAIN(db), value);
701
if (variables[i].save) {
712
CSException::throwException(CS_CONTEXT, HA_ERR_KEY_NOT_FOUND, name);
717
CSStringBuffer *MSVariableTable::dumpTable(MSDatabase *db)
721
CSStringBuffer *dump;
726
path = getSysVarFile(RETAIN(db->myDatabasePath));
730
new_(dump, CSStringBuffer(20));
733
if (path->exists()) {
737
file = path->openFile(CSFile::READONLY);
740
size = file->getEOF();
741
dump->setLength(size);
742
file->read(dump->getBuffer(0), 0, size, size);
751
void MSVariableTable::restoreTable(MSDatabase *db, const char *data, size_t size, bool reload)
759
path = getSysVarFile(RETAIN(db->myDatabasePath));
762
file = path->openFile(CSFile::CREATE | CSFile::TRUNCATE);
765
file->write(data, 0, size);
779
void MSVariableTable::removeTable(CSString *db_path)
784
path = getSysVarFile(db_path);