~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbms/src/blobcontainer_ms.cc

Added the PBMS daemon plugin.

(Augen zu und durch!)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#ifdef xxxDRIZZLED
 
2
/* 
 
3
   -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
4
   *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
5
 
 
6
   Copyright (C) 2006 MySQL AB
 
7
 
 
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.
 
11
 
 
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.
 
16
 
 
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 */
 
20
 
 
21
/* need to define DRIZZLE_SERVER to get inside the Session */
 
22
#define DRIZZLE_SERVER 1
 
23
 
 
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>
 
30
 
 
31
#include "CSConfig.h"
 
32
#include "CSGlobal.h"
 
33
#include "CSStrUtil.h"
 
34
#include "Engine_ms.h"
 
35
 
 
36
/*
 
37
        select * from information_schema.plugins;
 
38
 insert into bt values (13, "PBMS_BLOB xxxxxxxx", "zzzzzz", "Another pbms blob");
 
39
 select * from bt;
 
40
 
 
41
*/
 
42
#define NO_ERROR        false
 
43
#define ERROR   true
 
44
 
 
45
static ulong plugin_min_blob_size= 0;
 
46
 
 
47
static bool debug_trace= true;
 
48
 
 
49
void * (*blobcontainer_session_alloc)(Session *session, unsigned int size);
 
50
 
 
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
 
56
 
 
57
//-------------------
 
58
static int report_error(Session *session , PBMSResultRec *rec, const char *msg)
 
59
{
 
60
        if (rec) {
 
61
                if (msg)
 
62
                        errmsg_printf(session, NORMAL_PRIORITY, "PBMS blobcontainer: (%"PRId32") %s (%s)", rec->mr_code, rec->mr_message, msg);
 
63
                else
 
64
                        errmsg_printf(session, NORMAL_PRIORITY, "PBMS blobcontainer: (%"PRId32") %s", rec->mr_code, rec->mr_message);
 
65
        } else if (msg)
 
66
                errmsg_printf(session, NORMAL_PRIORITY, "PBMS blobcontainer: %s", msg);
 
67
                
 
68
        return ER_UNKNOWN_ERROR;
 
69
}
 
70
 
 
71
//-------------------
 
72
static bool local_insert_blob(Session *session, Field_blob *field, unsigned char **blob, uint32_t *len, int *error, bool can_create)
 
73
{
 
74
        char *out_url = NULL, blob_url_buffer[PBMS_BLOB_URL_SIZE], *in_url = (char *)*blob;
 
75
        size_t url_len = *len;
 
76
        bool retry = true;
 
77
        PBMSResultRec result = {0};
 
78
        
 
79
        *error= 0;
 
80
 
 
81
        if ((*len < plugin_min_blob_size) || !*blob)
 
82
                return NO_ERROR;
 
83
 
 
84
try_again:   
 
85
 
 
86
        out_url = pbms_use_blob(DB_NAME(field), TAB_NAME(field), field->field_index, in_url, url_len,  blob_url_buffer, &result);
 
87
        if (out_url) {
 
88
                if (*len < strlen(out_url)) {
 
89
                        *blob= (unsigned char *) blobcontainer_session_alloc(session, strlen(out_url));
 
90
                        if (!*blob) {
 
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;
 
93
                                goto done;
 
94
                        }    
 
95
                }
 
96
                *len= strlen(out_url);
 
97
                memcpy((char*)(*blob), out_url, *len);
 
98
 
 
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.");
 
102
                        goto done;
 
103
                }
 
104
        
 
105
                result.mr_code = 0;
 
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.");
 
108
                        goto done;
 
109
                }               
 
110
                in_url = blob_url_buffer;
 
111
                url_len = strlen(in_url);
 
112
                retry = false;
 
113
                goto try_again;
 
114
        } else
 
115
                *error = report_error(session, &result, "pbms_use_blob() failed.");
 
116
                
 
117
        
 
118
 
 
119
 done:
 
120
 
 
121
        return (*error != 0);
 
122
}
 
123
 
 
124
//-------------------
 
125
static bool local_delete_blob(Session *session, Field_blob *field, const unsigned char *blob, uint32_t len, int *error)
 
126
{
 
127
        PBMSResultRec result = {0};
 
128
        
 
129
        *error= 0;
 
130
 
 
131
        if (!blob)
 
132
                return NO_ERROR;
 
133
                
 
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.");
 
136
        }
 
137
        
 
138
        return (*error != 0);
 
139
}
 
140
 
 
141
//-------------------
 
142
static bool blobcontainer_insert_blob(Session *session, Field_blob *field, unsigned char **blob, uint32_t *len, int *error)
 
143
{
 
144
        if (pbms_enabled(ENG_NAME(field)) 
 
145
                return NO_ERROR;
 
146
                
 
147
        if (debug_trace) {
 
148
                char str[21];
 
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);
 
152
        }
 
153
 
 
154
        return local_insert_blob(session, field, blob, len, error, true);
 
155
}
 
156
 
 
157
//-------------------
 
158
static bool blobcontainer_undo_insert_blob(Session *session, Field_blob *field, unsigned char *blob, uint32_t len)
 
159
{
 
160
        int err;
 
161
        
 
162
        if (pbms_enabled(ENG_NAME(field)) 
 
163
                return NO_ERROR;
 
164
                
 
165
        if (debug_trace) 
 
166
                printf("blobcontainer_undo_insert_blob(%s.%s) called.\n", *(field->table_name), field->field_name);
 
167
 
 
168
        return local_delete_blob( session, field, blob, len, &err);
 
169
}
 
170
 
 
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)
 
172
{
 
173
        *error= 0;
 
174
        if (pbms_enabled(ENG_NAME(field)) 
 
175
                return NO_ERROR;
 
176
                
 
177
        if (debug_trace) {
 
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;
 
181
 
 
182
                memcpy(old_str, old_blob, (old_len < 21)?old_len:20);
 
183
                old_str[(old_len < 21)?old_len:20]= 0;
 
184
 
 
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);
 
186
        }
 
187
 
 
188
        if (local_insert_blob(session, field, blob, len, error, true) == ERROR)
 
189
                return ERROR;
 
190
 
 
191
        if (local_delete_blob(session, field, old_blob, old_len, error) == ERROR) {
 
192
                int err = 0;
 
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.");
 
195
                }                       
 
196
                return ERROR;
 
197
        }
 
198
 
 
199
        return NO_ERROR ;
 
200
}
 
201
 
 
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 )
 
203
{
 
204
        bool rtc1, rtc2;
 
205
        int err;
 
206
        unsigned char *temp_blob = (unsigned char *) old_blob;
 
207
        
 
208
        if (pbms_enabled(ENG_NAME(field)) 
 
209
                return NO_ERROR;
 
210
                
 
211
        if (debug_trace) 
 
212
                printf("blobcontainer_undo_update_blob(%s.%s) called.\n", *(field->table_name), field->field_name);
 
213
 
 
214
        
 
215
        rtc1 = local_insert_blob( session, field, &temp_blob, &old_len, &err, false);   
 
216
        rtc2 = local_delete_blob( session, field, blob, len, &err);
 
217
 
 
218
        if (rtc1 == ERROR || rtc1 == ERROR)
 
219
                return ERROR;
 
220
                
 
221
        return NO_ERROR ;
 
222
}
 
223
 
 
224
static bool blobcontainer_delete_blob(Session *session , Field_blob *field, const unsigned char *blob, uint32_t len, int *error)
 
225
{
 
226
        *error= 0;
 
227
        if (pbms_enabled(ENG_NAME(field)) 
 
228
                return NO_ERROR;
 
229
                
 
230
        if (debug_trace) {
 
231
                char str[21];
 
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);
 
235
        }
 
236
 
 
237
        return local_delete_blob(session, field, blob, len, error) ;
 
238
}
 
239
 
 
240
static bool blobcontainer_undo_delete_blob(Session *session, Field_blob *field, const unsigned char *blob, uint32_t len)
 
241
{
 
242
        unsigned char *temp_blob = (unsigned char *) blob;
 
243
        int err;
 
244
        if (pbms_enabled(ENG_NAME(field)) 
 
245
                return NO_ERROR;
 
246
                
 
247
        if (debug_trace) {
 
248
                char str[21];
 
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);
 
252
        }
 
253
 
 
254
        return local_insert_blob( session, field, &temp_blob, &len, &err, false);
 
255
}
 
256
 
 
257
static bool blobcontainer_rename_table(Session *session, const char *old_name, const  char *new_name, int *error)
 
258
{
 
259
        PBMSResultRec result = {0};
 
260
        char old_db_name[PATH_MAX], new_db_name[PATH_MAX], *old_table, *new_table;
 
261
        *error= 0;
 
262
        
 
263
        if (pbms_enabled(ENG_NAME(field)) 
 
264
                return NO_ERROR;
 
265
                
 
266
        if (debug_trace) 
 
267
                printf("blobcontainer_rename_table(%s, %s) called.\n", old_name, new_name);
 
268
 
 
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);
 
272
        
 
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);
 
276
        
 
277
        
 
278
        if (strcmp(old_db_name, new_db_name)) {
 
279
                *error = report_error(session, NULL, "Cannot rename tables across databases.");
 
280
                return ERROR;
 
281
        }
 
282
        
 
283
        
 
284
        
 
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.");
 
287
        }
 
288
 
 
289
        return (*error != 0);
 
290
}
 
291
 
 
292
static bool blobcontainer_undo_rename_table(Session *session, const char *old_name, const  char *new_name)
 
293
{
 
294
        int err;
 
295
        
 
296
        if (pbms_enabled(ENG_NAME(field)) 
 
297
                return NO_ERROR;
 
298
                
 
299
        if (debug_trace) 
 
300
                printf("blobcontainer_undo_rename_table(%s, %s) called.\n", old_name, new_name);
 
301
                
 
302
        return (blobcontainer_rename_table(session, new_name, old_name, &err));
 
303
}
 
304
 
 
305
static bool blobcontainer_drop_table(Session *session, const char *name, int *error)
 
306
{
 
307
        PBMSResultRec result = {0};
 
308
        char db_name[PATH_MAX], *table;
 
309
 
 
310
        *error= 0;
 
311
        if (pbms_enabled(ENG_NAME(field)) 
 
312
                return NO_ERROR;
 
313
                
 
314
        if (debug_trace) 
 
315
                printf("blobcontainer_drop_table(%s) called.\n", name);
 
316
 
 
317
        cs_strcpy(PATH_MAX, db_name, name);
 
318
        table = cs_last_name_of_path(db_name);
 
319
        if (table == db_name)
 
320
                return NO_ERROR;
 
321
                
 
322
        *(table -1) = 0;
 
323
        
 
324
        if (pbms_drop_table(cs_last_name_of_path(db_name), table,  &result)) {
 
325
                *error = report_error(session, &result, "pbms_drop_table() failed.");
 
326
        }
 
327
 
 
328
        return (*error != 0);
 
329
}
 
330
 
 
331
static bool blobcontainer_undo_drop_table(Session *session __attribute__((unused)), const char *name)
 
332
{
 
333
        if (pbms_enabled(ENG_NAME(field)) 
 
334
                return NO_ERROR;
 
335
                
 
336
        if (debug_trace) 
 
337
                printf("blobcontainer_undo_drop_table(%s) called.\n", name);
 
338
 
 
339
        return report_error(session,NULL, "Cannot undo DROP TABLE."); ;
 
340
}
 
341
 
 
342
 
 
343
static int pbms_blobfilter_plugin_init(void *p)
 
344
{
 
345
  blobcontainer_t *bc= (blobcontainer_t*) p;
 
346
  
 
347
  blobcontainer_session_alloc = bc->blobcontainer_session_alloc;
 
348
  
 
349
  bc->blobcontainer_insert_blob= blobcontainer_insert_blob;
 
350
  bc->blobcontainer_undo_insert_blob= blobcontainer_undo_insert_blob;
 
351
 
 
352
  bc->blobcontainer_update_blob= blobcontainer_update_blob;
 
353
  bc->blobcontainer_undo_update_blob= blobcontainer_undo_update_blob;
 
354
  
 
355
  bc->blobcontainer_delete_blob= blobcontainer_delete_blob;
 
356
  bc->blobcontainer_undo_delete_blob= blobcontainer_undo_delete_blob;
 
357
  
 
358
  bc->blobcontainer_rename_table= blobcontainer_rename_table;
 
359
  bc->blobcontainer_undo_rename_table= blobcontainer_undo_rename_table;
 
360
 
 
361
  bc->blobcontainer_drop_table= blobcontainer_drop_table;
 
362
  bc->blobcontainer_undo_drop_table= blobcontainer_undo_drop_table;
 
363
  
 
364
  if (debug_trace) 
 
365
    printf("pbms_blobfilter_plugin_init() called.\n");
 
366
 
 
367
  return 0;
 
368
}
 
369
 
 
370
static int pbms_blobfilter_plugin_deinit(void *p)
 
371
{
 
372
  blobcontainer_t *bc= (blobcontainer_t*) p;
 
373
  bc->blobcontainer_insert_blob= NULL;
 
374
  bc->blobcontainer_undo_insert_blob= NULL;
 
375
  
 
376
  bc->blobcontainer_update_blob= NULL;
 
377
  bc->blobcontainer_undo_update_blob= NULL;
 
378
  
 
379
  bc->blobcontainer_delete_blob= NULL;
 
380
  bc->blobcontainer_undo_delete_blob= NULL;
 
381
  
 
382
  bc->blobcontainer_rename_table= NULL;
 
383
  bc->blobcontainer_undo_rename_table= NULL;
 
384
 
 
385
  bc->blobcontainer_drop_table= NULL;
 
386
  bc->blobcontainer_undo_drop_table= NULL;
 
387
    
 
388
  return 0;
 
389
}
 
390
////////////////////////////////////////
 
391
 
 
392
class PBMS_Filter: public Filter
 
393
{
 
394
 
 
395
        PBMS_Filter(){}
 
396
        ~PBMS_Filter(){}
 
397
        
 
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;}
 
400
 
 
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;}
 
403
 
 
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;}
 
406
 
 
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;}
 
409
 
 
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;}
 
412
 
 
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;}
 
415
 
 
416
}
 
417
 
 
418
static PBMS_Filter *pbms_Filter= NULL;
 
419
static int pbms_blobfilter_plugin_init(drizzled::plugin::Registry &registry)
 
420
{
 
421
   PBMSResultRec result;
 
422
   if (!pbms_initialize("Drizzle", true, &result)) {
 
423
       sql_print_error("pbms_initialize() Error: %s", result.mr_message);
 
424
       return 1;
 
425
   }
 
426
 
 
427
  pbms_Filter = new PBMS_Filter();
 
428
  registry.add(pbms_Filter);
 
429
 
 
430
  return 0;
 
431
}
 
432
 
 
433
static int pbms_blobfilter_plugin_deinit(drizzled::plugin::Registry &registry)
 
434
{
 
435
        registry.remove(pbms_Filter);
 
436
        delete pbms_Filter;
 
437
        pbms_Filter= NULL;
 
438
 
 
439
        pbms_finalize();
 
440
        return 0;
 
441
}
 
442
 
 
443
 
 
444
 
 
445
#ifdef BLOBFILTER_SYSTEM_VARS
 
446
static DRIZZLE_SYSVAR_BOOL(
 
447
  tracing_enable,
 
448
  debug_trace,
 
449
  PLUGIN_VAR_NOCMDARG,
 
450
  "Enable plugin tracing",
 
451
  NULL, /* check func */
 
452
  NULL, /* update func */
 
453
  false /* default */);
 
454
 
 
455
static DRIZZLE_SYSVAR_ULONG(
 
456
  min_blob_size,
 
457
  plugin_min_blob_size,
 
458
  PLUGIN_VAR_OPCMDARG,
 
459
  "Minimum BLOB size to be stored.",
 
460
  NULL, /* check func */
 
461
  NULL, /* update func */
 
462
  0, /* default */
 
463
  0, /* min */
 
464
  ULONG_MAX, /* max */
 
465
  0 /* blksiz */);
 
466
 
 
467
static struct st_mysql_sys_var* pbms_blobfilter_system_variables[]= {
 
468
  DRIZZLE_SYSVAR(tracing_enable),
 
469
  DRIZZLE_SYSVAR(min_blob_size),
 
470
  NULL
 
471
};
 
472
#else
 
473
#define pbms_blobfilter_system_variables NULL
 
474
#endif
 
475
 
 
476
//struct st_mysql_plugin pbms_blobcontainer_plugin = {
 
477
//  DRIZZLE_FILTER_PLUGIN,
 
478
drizzle_declare_plugin(blobfilter)
 
479
{
 
480
  "PBMS BLOB Filter",
 
481
  "1.0",
 
482
  "Barry Leslie  PrimeBase Technologies GmbH",
 
483
  "BLOB filter plugin for the PBMS storage engine.",
 
484
  PLUGIN_LICENSE_GPL,
 
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 */
 
490
};
 
491
 
 
492
#endif // DRIZZLED