3
-*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
4
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
6
Copyright (C) 2006 MySQL AB
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; version 2 of the License.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
21
/* need to define DRIZZLE_SERVER to get inside the Session */
22
#define DRIZZLE_SERVER 1
24
#include <drizzled/server_includes.h>
25
#include <drizzled/plugin_blobcontainer.h>
26
#include <drizzled/table.h>
27
#include <drizzled/gettext.h>
28
#include <drizzled/errmsg.h>
29
#include <drizzled/error.h>
33
#include "CSStrUtil.h"
34
#include "Engine_ms.h"
37
select * from information_schema.plugins;
38
insert into bt values (13, "PBMS_BLOB xxxxxxxx", "zzzzzz", "Another pbms blob");
42
#define NO_ERROR false
45
static ulong plugin_min_blob_size= 0;
47
static bool debug_trace= true;
49
void * (*blobcontainer_session_alloc)(Session *session, unsigned int size);
51
#define DB_NAME(f) (f->table->s->db.str)
52
#define TAB_NAME(f) (*(f->table_name))
53
#define ENG_NAME(f) (f->table->s->db_plugin->name.str)
54
#define DUMMY_URL "PBMS_BLOB_URL"
55
#define NORMAL_PRIORITY 1
58
static int report_error(Session *session , PBMSResultRec *rec, const char *msg)
62
errmsg_printf(session, NORMAL_PRIORITY, "PBMS blobcontainer: (%"PRId32") %s (%s)", rec->mr_code, rec->mr_message, msg);
64
errmsg_printf(session, NORMAL_PRIORITY, "PBMS blobcontainer: (%"PRId32") %s", rec->mr_code, rec->mr_message);
66
errmsg_printf(session, NORMAL_PRIORITY, "PBMS blobcontainer: %s", msg);
68
return ER_UNKNOWN_ERROR;
72
static bool local_insert_blob(Session *session, Field_blob *field, unsigned char **blob, uint32_t *len, int *error, bool can_create)
74
char *out_url = NULL, blob_url_buffer[PBMS_BLOB_URL_SIZE], *in_url = (char *)*blob;
75
size_t url_len = *len;
77
PBMSResultRec result = {0};
81
if ((*len < plugin_min_blob_size) || !*blob)
86
out_url = pbms_use_blob(DB_NAME(field), TAB_NAME(field), field->field_index, in_url, url_len, blob_url_buffer, &result);
88
if (*len < strlen(out_url)) {
89
*blob= (unsigned char *) blobcontainer_session_alloc(session, strlen(out_url));
91
(void) pbms_release_blob(DB_NAME(field), TAB_NAME(field), field->field_index, out_url, strlen(out_url), &result);
92
*error= HA_ERR_OUT_OF_MEM;
96
*len= strlen(out_url);
97
memcpy((char*)(*blob), out_url, *len);
99
} else if ((result.mr_code == MS_ERR_INCORRECT_URL) && can_create) { // The data is not a url.
100
if (!retry) { // This should never happen.
101
*error = report_error(session, NULL, "Bad PBMS BLOB URL generated.");
106
if ( pbms_new_blob(DB_NAME(field), TAB_NAME(field), field->field_index, *blob, *len, blob_url_buffer, &result)) {
107
*error = report_error(session, &result, "pbms_new_blob() failed.");
110
in_url = blob_url_buffer;
111
url_len = strlen(in_url);
115
*error = report_error(session, &result, "pbms_use_blob() failed.");
121
return (*error != 0);
124
//-------------------
125
static bool local_delete_blob(Session *session, Field_blob *field, const unsigned char *blob, uint32_t len, int *error)
127
PBMSResultRec result = {0};
134
if (pbms_release_blob(DB_NAME(field), TAB_NAME(field), field->field_index, (char*)blob, len, &result)) {
135
*error = report_error(session, &result, "pbms_new_blob() failed.");
138
return (*error != 0);
141
//-------------------
142
static bool blobcontainer_insert_blob(Session *session, Field_blob *field, unsigned char **blob, uint32_t *len, int *error)
144
if (pbms_enabled(ENG_NAME(field))
149
memcpy(str, *blob, (*len < 21)?*len:20);
150
str[(*len < 21)?*len:20]= 0;
151
printf("blobcontainer_insert_blob(%s.%s, \"%s\", %"PRId32") called.\n", *(field->table_name), field->field_name, str, *len);
154
return local_insert_blob(session, field, blob, len, error, true);
157
//-------------------
158
static bool blobcontainer_undo_insert_blob(Session *session, Field_blob *field, unsigned char *blob, uint32_t len)
162
if (pbms_enabled(ENG_NAME(field))
166
printf("blobcontainer_undo_insert_blob(%s.%s) called.\n", *(field->table_name), field->field_name);
168
return local_delete_blob( session, field, blob, len, &err);
171
static bool blobcontainer_update_blob(Session *session, Field_blob *field, const unsigned char *old_blob, uint32_t old_len, unsigned char **blob, uint32_t *len, int *error)
174
if (pbms_enabled(ENG_NAME(field))
178
char new_str[21], old_str[21];
179
memcpy(new_str, *blob, (*len < 21)?*len:20);
180
new_str[(*len < 21)?*len:20]= 0;
182
memcpy(old_str, old_blob, (old_len < 21)?old_len:20);
183
old_str[(old_len < 21)?old_len:20]= 0;
185
printf("blobcontainer_update_blob(%s.%s, \"%s\", %"PRId32", \"%s\", %"PRId32") called.\n", *(field->table_name), field->field_name, old_str, old_len, new_str, *len);
188
if (local_insert_blob(session, field, blob, len, error, true) == ERROR)
191
if (local_delete_blob(session, field, old_blob, old_len, error) == ERROR) {
193
if (local_delete_blob(session, field, *blob, *len, &err) == ERROR) { // Should never happen.
194
report_error(session, NULL, "Cleanup after failed update failed. Possible non referenced BLOB.");
202
static bool blobcontainer_undo_update_blob(Session *session, Field_blob *field, const unsigned char *old_blob , uint32_t old_len , unsigned char *blob , uint32_t len )
206
unsigned char *temp_blob = (unsigned char *) old_blob;
208
if (pbms_enabled(ENG_NAME(field))
212
printf("blobcontainer_undo_update_blob(%s.%s) called.\n", *(field->table_name), field->field_name);
215
rtc1 = local_insert_blob( session, field, &temp_blob, &old_len, &err, false);
216
rtc2 = local_delete_blob( session, field, blob, len, &err);
218
if (rtc1 == ERROR || rtc1 == ERROR)
224
static bool blobcontainer_delete_blob(Session *session , Field_blob *field, const unsigned char *blob, uint32_t len, int *error)
227
if (pbms_enabled(ENG_NAME(field))
232
memcpy(str, blob, (len < 21)?len:20);
233
str[(len < 21)?len:20]= 0;
234
printf("blobcontainer_delete_blob(%s.%s, \"%s\", %"PRId32") called.\n", *(field->table_name), field->field_name, str, len);
237
return local_delete_blob(session, field, blob, len, error) ;
240
static bool blobcontainer_undo_delete_blob(Session *session, Field_blob *field, const unsigned char *blob, uint32_t len)
242
unsigned char *temp_blob = (unsigned char *) blob;
244
if (pbms_enabled(ENG_NAME(field))
249
memcpy(str, blob, (len < 21)?len:20);
250
str[(len < 21)?len:20]= 0;
251
printf("blobcontainer_undo_delete_blob(%s.%s, \"%s\", %"PRId32") called.\n", *(field->table_name), field->field_name, str, len);
254
return local_insert_blob( session, field, &temp_blob, &len, &err, false);
257
static bool blobcontainer_rename_table(Session *session, const char *old_name, const char *new_name, int *error)
259
PBMSResultRec result = {0};
260
char old_db_name[PATH_MAX], new_db_name[PATH_MAX], *old_table, *new_table;
263
if (pbms_enabled(ENG_NAME(field))
267
printf("blobcontainer_rename_table(%s, %s) called.\n", old_name, new_name);
269
cs_strcpy(PATH_MAX, old_db_name, old_name);
270
old_table = cs_last_name_of_path(old_db_name);
271
cs_remove_last_name_of_path(old_db_name);
273
cs_strcpy(PATH_MAX, new_db_name, new_name);
274
new_table = cs_last_name_of_path(new_db_name);
275
cs_remove_last_name_of_path(new_db_name);
278
if (strcmp(old_db_name, new_db_name)) {
279
*error = report_error(session, NULL, "Cannot rename tables across databases.");
285
if (pbms_rename_table(cs_last_name_of_path(new_db_name), old_table, new_table, &result)) {
286
*error = report_error(session, &result, "pbms_rename_table() failed.");
289
return (*error != 0);
292
static bool blobcontainer_undo_rename_table(Session *session, const char *old_name, const char *new_name)
296
if (pbms_enabled(ENG_NAME(field))
300
printf("blobcontainer_undo_rename_table(%s, %s) called.\n", old_name, new_name);
302
return (blobcontainer_rename_table(session, new_name, old_name, &err));
305
static bool blobcontainer_drop_table(Session *session, const char *name, int *error)
307
PBMSResultRec result = {0};
308
char db_name[PATH_MAX], *table;
311
if (pbms_enabled(ENG_NAME(field))
315
printf("blobcontainer_drop_table(%s) called.\n", name);
317
cs_strcpy(PATH_MAX, db_name, name);
318
table = cs_last_name_of_path(db_name);
319
if (table == db_name)
324
if (pbms_drop_table(cs_last_name_of_path(db_name), table, &result)) {
325
*error = report_error(session, &result, "pbms_drop_table() failed.");
328
return (*error != 0);
331
static bool blobcontainer_undo_drop_table(Session *session __attribute__((unused)), const char *name)
333
if (pbms_enabled(ENG_NAME(field))
337
printf("blobcontainer_undo_drop_table(%s) called.\n", name);
339
return report_error(session,NULL, "Cannot undo DROP TABLE."); ;
343
static int pbms_blobfilter_plugin_init(void *p)
345
blobcontainer_t *bc= (blobcontainer_t*) p;
347
blobcontainer_session_alloc = bc->blobcontainer_session_alloc;
349
bc->blobcontainer_insert_blob= blobcontainer_insert_blob;
350
bc->blobcontainer_undo_insert_blob= blobcontainer_undo_insert_blob;
352
bc->blobcontainer_update_blob= blobcontainer_update_blob;
353
bc->blobcontainer_undo_update_blob= blobcontainer_undo_update_blob;
355
bc->blobcontainer_delete_blob= blobcontainer_delete_blob;
356
bc->blobcontainer_undo_delete_blob= blobcontainer_undo_delete_blob;
358
bc->blobcontainer_rename_table= blobcontainer_rename_table;
359
bc->blobcontainer_undo_rename_table= blobcontainer_undo_rename_table;
361
bc->blobcontainer_drop_table= blobcontainer_drop_table;
362
bc->blobcontainer_undo_drop_table= blobcontainer_undo_drop_table;
365
printf("pbms_blobfilter_plugin_init() called.\n");
370
static int pbms_blobfilter_plugin_deinit(void *p)
372
blobcontainer_t *bc= (blobcontainer_t*) p;
373
bc->blobcontainer_insert_blob= NULL;
374
bc->blobcontainer_undo_insert_blob= NULL;
376
bc->blobcontainer_update_blob= NULL;
377
bc->blobcontainer_undo_update_blob= NULL;
379
bc->blobcontainer_delete_blob= NULL;
380
bc->blobcontainer_undo_delete_blob= NULL;
382
bc->blobcontainer_rename_table= NULL;
383
bc->blobcontainer_undo_rename_table= NULL;
385
bc->blobcontainer_drop_table= NULL;
386
bc->blobcontainer_undo_drop_table= NULL;
390
////////////////////////////////////////
392
class PBMS_Filter: public Filter
398
virtual bool insert_row(Table *table, void *buf, int *error){return false;}
399
virtual bool complete_insert_row(Table *table, void *buf, bool undo){return false;}
401
virtual bool update_row(Table *table, const void *old_data, void *new_data, int *error){return false;}
402
virtual bool complete_update_row(Table *table, const void *old_data, void *new_data, bool undo){return false;}
404
virtual bool delete_row(Table *table, const void *buf, int *error){return false;}
405
virtual bool complete_delete_row(Table *table, const void *buf, int *error){return false;}
407
virtual bool delete_row(Table *table, const void *buf, int *error){return false;}
408
virtual bool complete_delete_row(Table *table, const void *buf, bool undo){return false;}
410
virtual bool rename_table(const char *old_table_path, const char *new_table_path, int *error){return false;}
411
virtual bool complete_rename_table(const char *old_table_path, const char *new_table_path, bool undo){return false;}
413
virtual bool drop_table(const char *table_path, int *error){return false;}
414
virtual bool complete_drop_table(const char *table_path, bool undo){return false;}
418
static PBMS_Filter *pbms_Filter= NULL;
419
static int pbms_blobfilter_plugin_init(drizzled::plugin::Registry ®istry)
421
PBMSResultRec result;
422
if (!pbms_initialize("Drizzle", true, &result)) {
423
sql_print_error("pbms_initialize() Error: %s", result.mr_message);
427
pbms_Filter = new PBMS_Filter();
428
registry.add(pbms_Filter);
433
static int pbms_blobfilter_plugin_deinit(drizzled::plugin::Registry ®istry)
435
registry.remove(pbms_Filter);
445
#ifdef BLOBFILTER_SYSTEM_VARS
446
static DRIZZLE_SYSVAR_BOOL(
450
"Enable plugin tracing",
451
NULL, /* check func */
452
NULL, /* update func */
453
false /* default */);
455
static DRIZZLE_SYSVAR_ULONG(
457
plugin_min_blob_size,
459
"Minimum BLOB size to be stored.",
460
NULL, /* check func */
461
NULL, /* update func */
467
static struct st_mysql_sys_var* pbms_blobfilter_system_variables[]= {
468
DRIZZLE_SYSVAR(tracing_enable),
469
DRIZZLE_SYSVAR(min_blob_size),
473
#define pbms_blobfilter_system_variables NULL
476
//struct st_mysql_plugin pbms_blobcontainer_plugin = {
477
// DRIZZLE_FILTER_PLUGIN,
478
drizzle_declare_plugin(blobfilter)
482
"Barry Leslie PrimeBase Technologies GmbH",
483
"BLOB filter plugin for the PBMS storage engine.",
485
pbms_blobfilter_plugin_init, /* Plugin Init */
486
pbms_blobfilter_plugin_deinit, /* Plugin Deinit */
487
NULL, /* status variables */
488
pbms_blobfilter_system_variables,
489
NULL /* config options */