~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2010-07-06 00:44:32 UTC
  • mfrom: (1643.1.13 build)
  • Revision ID: mordred@inaugust.com-20100706004432-843uftc92rc2497l
Merged in PBMS, translation updates, a few build fixes and a few bug fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2010 PrimeBase Technologies GmbH, Germany
 
2
 *
 
3
 * PrimeBase Media Stream for MySQL
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 
18
 *
 
19
 * Barry Leslie
 
20
 *
 
21
 * 2010-05-25
 
22
 *
 
23
 * PBMS daemon global parameters.
 
24
 *
 
25
 */
 
26
 
 
27
#ifdef DRIZZLED
 
28
#include "config.h"
 
29
#include <set>
 
30
#include <drizzled/common.h>
 
31
#include <drizzled/plugin.h>
 
32
#include <drizzled/session.h>
 
33
using namespace drizzled;
 
34
using namespace drizzled::plugin;
 
35
 
 
36
#define my_strdup(a,b) strdup(a)
 
37
 
 
38
#include "cslib/CSConfig.h"
 
39
#else
 
40
#include "cslib/CSConfig.h"
 
41
#include "mysql_priv.h"
 
42
#include <mysql/plugin.h>
 
43
#include <my_dir.h>
 
44
#endif 
 
45
 
 
46
#include <inttypes.h>
 
47
 
 
48
#include "cslib/CSDefs.h"
 
49
#include "cslib/CSObject.h"
 
50
#include "cslib/CSGlobal.h"
 
51
#include "cslib/CSThread.h"
 
52
#include "cslib/CSStrUtil.h"
 
53
#include "cslib/CSPath.h"
 
54
#include "cslib/CSLog.h"
 
55
 
 
56
#include "defs_ms.h"
 
57
#include "database_ms.h"
 
58
#include "parameters_ms.h"
 
59
 
 
60
#ifndef PBMS_PORT
 
61
#define PBMS_PORT 8080
 
62
#endif
 
63
 
 
64
 
 
65
static int my_port_number = PBMS_PORT;
 
66
 
 
67
static char             *my_repository_threshold = NULL;
 
68
static char             *my_temp_log_threshold = NULL;
 
69
static char             *my_http_metadata_headers = NULL;
 
70
 
 
71
static u_long   my_temp_blob_timeout = MS_DEFAULT_TEMP_LOG_WAIT;
 
72
static u_long   my_garbage_threshold = MS_DEFAULT_GARBAGE_LEVEL;
 
73
static u_long   my_max_keep_alive = MS_DEFAULT_KEEP_ALIVE;
 
74
 
 
75
static uint64_t my_backup_db_id = 1;
 
76
static uint32_t my_server_id = 1;
 
77
 
 
78
#ifdef DRIZZLED
 
79
static set<string> my_black_list;
 
80
static bool my_events_enabled = true;
 
81
static CSMutex my_table_list_lock;
 
82
 
 
83
typedef enum {MATCH_ALL, MATCH_DBS, MATCH_SOME, MATCH_NONE, MATCH_UNKNOWN, MATCH_ERROR} TableMatchState;
 
84
static char *my_table_list = NULL;
 
85
static const char *dflt_my_table_list = "*";
 
86
 
 
87
static TableMatchState my_table_match = MATCH_UNKNOWN;
 
88
 
 
89
static int32_t my_before_insert_position= 1;      // Call this event observer first.
 
90
static int32_t my_before_update_position= 1;
 
91
 
 
92
using namespace drizzled;
 
93
using namespace drizzled::plugin;
 
94
 
 
95
#define st_mysql_sys_var drizzled::drizzle_sys_var
 
96
#else
 
97
 
 
98
struct st_mysql_sys_var
 
99
{
 
100
  MYSQL_PLUGIN_VAR_HEADER;
 
101
};
 
102
 
 
103
#endif
 
104
 
 
105
#if MYSQL_VERSION_ID < 60000
 
106
 
 
107
#if MYSQL_VERSION_ID >= 50124
 
108
#define CONST_SAVE const
 
109
#endif
 
110
 
 
111
#else
 
112
 
 
113
#if MYSQL_VERSION_ID >= 60005
 
114
#define CONST_SAVE const
 
115
#endif
 
116
 
 
117
#endif
 
118
 
 
119
#ifndef CONST_SAVE
 
120
#define CONST_SAVE 
 
121
#endif
 
122
 
 
123
//--------------
 
124
uint32_t PBMSParameters::getPortNumber(){ return my_port_number;}
 
125
 
 
126
//--------------
 
127
uint32_t PBMSParameters::getServerID(){ return my_server_id;}
 
128
 
 
129
//--------------
 
130
uint64_t PBMSParameters::getRepoThreshold()
 
131
{
 
132
        if (my_repository_threshold)
 
133
                return((uint64_t) cs_byte_size_to_int8(my_repository_threshold));
 
134
 
 
135
        return((uint64_t) cs_byte_size_to_int8(MS_REPO_THRESHOLD_DEF));
 
136
}
 
137
 
 
138
//--------------
 
139
uint64_t PBMSParameters::getTempLogThreshold()
 
140
{
 
141
        if (my_temp_log_threshold)
 
142
                return((uint64_t) cs_byte_size_to_int8(my_temp_log_threshold));
 
143
 
 
144
        return((uint64_t) cs_byte_size_to_int8(MS_TEMP_LOG_THRESHOLD_DEF));
 
145
}
 
146
 
 
147
//--------------
 
148
uint32_t PBMSParameters::getTempBlobTimeout(){ return my_temp_blob_timeout;}
 
149
 
 
150
//--------------
 
151
uint32_t PBMSParameters::getGarbageThreshold(){ return my_garbage_threshold;}
 
152
 
 
153
//--------------
 
154
uint32_t PBMSParameters::getMaxKeepAlive(){ return my_max_keep_alive;}
 
155
 
 
156
//--------------
 
157
const char * PBMSParameters::getDefaultMetaDataHeaders()
 
158
{
 
159
        if (my_http_metadata_headers)
 
160
                return my_http_metadata_headers; 
 
161
                
 
162
        return MS_HTTP_METADATA_HEADERS_DEF; 
 
163
}
 
164
 
 
165
//-----------------
 
166
uint64_t PBMSParameters::getBackupDatabaseID() { return my_backup_db_id;}
 
167
 
 
168
//-----------------
 
169
void PBMSParameters::setBackupDatabaseID(uint64_t id) { my_backup_db_id = id;}
 
170
 
 
171
#ifdef DRIZZLED
 
172
//-----------------
 
173
bool PBMSParameters::isPBMSEventsEnabled() { return my_events_enabled;}
 
174
 
 
175
 
 
176
#define NEXT_IN_TABLE_LIST(list) {\
 
177
        while ((*list) && (*list != ',')) list++;\
 
178
        if (*list) list++;\
 
179
}
 
180
        
 
181
static TableMatchState set_match_type(const char *list)
 
182
{
 
183
        const char *ptr = list;
 
184
        const char *name;
 
185
        int name_len;
 
186
        TableMatchState match_state;
 
187
 
 
188
        if (!list)
 
189
                return MATCH_ALL;
 
190
                
 
191
        if (!ptr) {
 
192
                return MATCH_NONE;
 
193
        }
 
194
        
 
195
        while ((*ptr) && isspace(*ptr)) ptr++;
 
196
        if (!*ptr) {
 
197
                return MATCH_NONE;
 
198
        }
 
199
        
 
200
        match_state = MATCH_UNKNOWN;
 
201
 
 
202
        while (*ptr) {
 
203
        
 
204
                // Check database name
 
205
                name = ptr;
 
206
                name_len = 0;
 
207
                while ((*ptr) && (!isspace(*ptr)) && (*ptr != ',') && (*ptr != '.')) {ptr++;name_len++;}
 
208
                while ((*ptr) && isspace(*ptr)) ptr++;
 
209
                
 
210
                if (*ptr != '.') {
 
211
                        if ((name_len == 1) && (*name == '*'))
 
212
                                match_state = MATCH_ALL;
 
213
                        else
 
214
                                goto bad_list; // Missing table
 
215
                } else {
 
216
                
 
217
                        if ((match_state > MATCH_DBS) && (name_len == 1) && (*name == '*'))
 
218
                                match_state = MATCH_DBS;
 
219
                                
 
220
                        ptr++; // Skip the '.'
 
221
                        
 
222
                        // Find the start of the table name.
 
223
                        while ((*ptr) && isspace(*ptr)) ptr++;
 
224
                        if ((!*ptr) || (*ptr == ',') || (*ptr == '.'))
 
225
                                goto bad_list; // Missing table
 
226
                                
 
227
                        // Find the end of the table name.
 
228
                        while ((*ptr) && (!isspace(*ptr)) && (*ptr != ',') && (*ptr != '.')) ptr++;
 
229
                }
 
230
                
 
231
                // Locate the end of the element.
 
232
                while ((*ptr) && isspace(*ptr)) ptr++;
 
233
                                
 
234
                if ((*ptr) && (*ptr != ','))
 
235
                        goto bad_list; // Bad table name
 
236
                        
 
237
                if (match_state > MATCH_SOME)
 
238
                        match_state = MATCH_SOME;
 
239
                        
 
240
                if (*ptr) ptr++;
 
241
                while ((*ptr) && isspace(*ptr)) ptr++;
 
242
        }
 
243
        
 
244
        return match_state;
 
245
bad_list:
 
246
 
 
247
        char info[120];
 
248
        snprintf(info, 120, "pbms_watch_tables format error near character position %d", (int) (ptr - list));
 
249
        CSL.logLine(NULL, CSLog::Error, info);
 
250
        CSL.logLine(NULL, CSLog::Error, list);
 
251
        
 
252
        return MATCH_ERROR;
 
253
}
 
254
 
 
255
//-----------------
 
256
static const char* locate_db(const char *list, const char *db, int len)
 
257
{
 
258
        int match_len;
 
259
        
 
260
        while (*list) {
 
261
                while ((*list) && isspace(*list)) list++;
 
262
                if ((*list == 0) || (*(list+1) == 0) || (*(list+2) == 0)) // We need at least 3 characters
 
263
                        return NULL;
 
264
                
 
265
                match_len = 0;
 
266
                if (*list == '*') 
 
267
                        match_len = 1;
 
268
                else if (strncmp(list, db, len) == 0) 
 
269
                        match_len = len;
 
270
                
 
271
                if (match_len) {
 
272
                        list += match_len;
 
273
                        
 
274
                        // Find the '.'
 
275
                        while ((*list) && isspace(*list)) list++;
 
276
                        if ((*list == 0) || (*(list+1) == 0) ) // We need at least 2 characters
 
277
                                return NULL;
 
278
                                                
 
279
                        if (*list == '.') { 
 
280
                                list++;
 
281
                                while ((*list) && isspace(*list)) list++;
 
282
                                if (*list == 0)
 
283
                                         return NULL;
 
284
                                         
 
285
                                return list; // We have gound a table that could belong to this database;
 
286
                        }
 
287
                }
 
288
                
 
289
                NEXT_IN_TABLE_LIST(list);
 
290
        }
 
291
        
 
292
        return NULL;
 
293
}
 
294
 
 
295
//--------------
 
296
// Parameter update functions are not called for parameters that are set on
 
297
// the command line. PBMSParameters::startUp() will perform any initialization required.
 
298
void PBMSParameters::startUp()
 
299
 
300
        my_table_match = set_match_type(my_table_list);
 
301
}
 
302
 
 
303
//-----------------
 
304
bool PBMSParameters::isBlackListedDB(const char *db)
 
305
{
 
306
        if (my_black_list.find(string(db)) == my_black_list.end())
 
307
                return false;
 
308
                
 
309
        return true;
 
310
}               
 
311
 
 
312
//-----------------
 
313
void PBMSParameters::blackListedDB(const char *db)
 
314
{
 
315
        my_black_list.insert(string(db));
 
316
}               
 
317
 
 
318
//-----------------
 
319
bool PBMSParameters::isBLOBDatabase(const char *db)
 
320
{
 
321
        CSThread *self;
 
322
        int             err;
 
323
        PBMSResultRec result;
 
324
        bool found = false;
 
325
        
 
326
        if (isBlackListedDB(db))
 
327
                return false;
 
328
                
 
329
        if (my_table_match == MATCH_UNKNOWN)
 
330
                my_table_match = set_match_type(my_table_list);
 
331
 
 
332
        if (my_table_match == MATCH_NONE)
 
333
                return false;
 
334
 
 
335
        if (my_table_match <= MATCH_DBS)
 
336
                return true;
 
337
        
 
338
        if ((err = MSEngine::enterConnectionNoThd(&self, &result)) == 0) {
 
339
 
 
340
                inner_();
 
341
                try_(a) {
 
342
                        lock_(&my_table_list_lock);     
 
343
                        
 
344
                                
 
345
                        found = (locate_db(my_table_list, db, strlen(db)) != NULL);
 
346
                                
 
347
                        unlock_(&my_table_list_lock);
 
348
                }
 
349
                
 
350
                catch_(a) {
 
351
                        err = MSEngine::exceptionToResult(&self->myException, &result);
 
352
                }
 
353
                cont_(a);
 
354
                outer_();
 
355
        
 
356
        }
 
357
        
 
358
        if (err) {
 
359
                fprintf(stderr, "PBMSParameters::isBLOBDatabase(\"%s\") error (%d):'%s'\n", 
 
360
                        db, result.mr_code,  result.mr_message);
 
361
        }
 
362
        
 
363
        return found;
 
364
}
 
365
        
 
366
//-----------------
 
367
bool PBMSParameters::isBLOBTable(const char *db, const char *table)
 
368
{
 
369
        CSThread *self;
 
370
        int             err;
 
371
        PBMSResultRec result;
 
372
        bool found = false;
 
373
        const char *ptr;
 
374
        int db_len, table_len, match_len;
 
375
        
 
376
        if (isBlackListedDB(db))
 
377
                return false;
 
378
                
 
379
        if (my_table_match == MATCH_UNKNOWN)
 
380
                my_table_match = set_match_type(my_table_list);
 
381
 
 
382
        if (my_table_match == MATCH_NONE)
 
383
                return false;
 
384
 
 
385
        if (my_table_match <= MATCH_ALL)
 
386
                return true;
 
387
 
 
388
        if ((err = MSEngine::enterConnectionNoThd(&self, &result)) == 0) {
 
389
 
 
390
                inner_();
 
391
                try_(a) {
 
392
                        lock_(&my_table_list_lock);     
 
393
                                        
 
394
                        db_len = strlen(db);
 
395
                        table_len = strlen(table);
 
396
                        
 
397
                        ptr = my_table_list;
 
398
                        while (ptr) {
 
399
                                ptr = locate_db(ptr, db, db_len);
 
400
                                if (ptr) {
 
401
                                        match_len = 0;
 
402
                                        if (*ptr == '*')
 
403
                                                match_len = 1;
 
404
                                        else if (strncmp(ptr, table, table_len) == 0)
 
405
                                                match_len = table_len;
 
406
                                                
 
407
                                        if (match_len) {
 
408
                                                ptr += match_len;
 
409
                                                if ((!*ptr) || (*ptr == ',') || isspace(*ptr)) {
 
410
                                                        found = true;
 
411
                                                        break;
 
412
                                                }
 
413
                                        }
 
414
                                        
 
415
                                        NEXT_IN_TABLE_LIST(ptr);
 
416
                                }
 
417
                        }
 
418
                                
 
419
                        unlock_(&my_table_list_lock);
 
420
                }
 
421
                catch_(a) {
 
422
                        err = MSEngine::exceptionToResult(&self->myException, &result);
 
423
                }
 
424
                cont_(a);
 
425
                outer_();
 
426
        
 
427
        }
 
428
        
 
429
        if (err) {
 
430
                fprintf(stderr, "PBMSParameters::isBLOBTable(\"%s\", \"%s\") error (%d):'%s'\n", 
 
431
                        db, table, result.mr_code,  result.mr_message);
 
432
        }
 
433
        
 
434
        return found;
 
435
}
 
436
 
 
437
 
 
438
//-----------------
 
439
int32_t PBMSParameters::getBeforeUptateEventPosition() { return my_before_update_position;}
 
440
 
 
441
//-----------------
 
442
int32_t PBMSParameters::getBeforeInsertEventPosition() { return my_before_insert_position;}
 
443
#endif // DRIZZLED
 
444
 
 
445
//-----------------
 
446
static void pbms_temp_blob_timeout_func(THD *, struct st_mysql_sys_var *, void *, CONST_SAVE void *)
 
447
{
 
448
        CSThread                *self;
 
449
        PBMSResultRec   result;
 
450
 
 
451
        if (MSEngine::enterConnectionNoThd(&self, &result))
 
452
                return;
 
453
        try_(a) {
 
454
                MSDatabase::wakeTempLogThreads();
 
455
        }
 
456
        
 
457
        catch_(a);
 
458
        cont_(a);
 
459
}
 
460
 
 
461
//-----------------
 
462
//-----------------
 
463
static MYSQL_SYSVAR_INT(port, my_port_number,
 
464
        PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
465
        "The port for the server stream-based communications.",
 
466
        NULL, NULL, PBMS_PORT, 0, 64*1024, 1);
 
467
 
 
468
static MYSQL_SYSVAR_STR(repository_threshold, my_repository_threshold,
 
469
        PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
 
470
        "The maximum size of a BLOB repository file.",
 
471
        NULL, NULL, MS_REPO_THRESHOLD_DEF);
 
472
 
 
473
static MYSQL_SYSVAR_STR(temp_log_threshold, my_temp_log_threshold,
 
474
        PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
 
475
        "The maximum size of a temorary BLOB log file.",
 
476
        NULL, NULL, MS_TEMP_LOG_THRESHOLD_DEF);
 
477
 
 
478
static MYSQL_SYSVAR_STR(http_metadata_headers, my_http_metadata_headers,
 
479
        PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
 
480
        "A ':' delimited list of metadata header names to be used to initialize the pbms_metadata_header table when a database is created.",
 
481
        NULL, NULL , MS_HTTP_METADATA_HEADERS_DEF);
 
482
 
 
483
static MYSQL_SYSVAR_ULONG(temp_blob_timeout, my_temp_blob_timeout,
 
484
        PLUGIN_VAR_OPCMDARG,
 
485
        "The timeout, in seconds, for temporary BLOBs. Uploaded blob data is removed after this time, unless committed to the database.",
 
486
        NULL, pbms_temp_blob_timeout_func, MS_DEFAULT_TEMP_LOG_WAIT, 1, ~0L, 1);
 
487
 
 
488
static MYSQL_SYSVAR_ULONG(garbage_threshold, my_garbage_threshold,
 
489
        PLUGIN_VAR_OPCMDARG,
 
490
        "The percentage of garbage in a repository file before it is compacted.",
 
491
        NULL, NULL, MS_DEFAULT_GARBAGE_LEVEL, 0, 100, 1);
 
492
 
 
493
 
 
494
static MYSQL_SYSVAR_ULONG(max_keep_alive, my_max_keep_alive,
 
495
        PLUGIN_VAR_OPCMDARG,
 
496
        "The timeout, in milli-seconds, before the HTTP server will close an inactive HTTP connection.",
 
497
        NULL, NULL, MS_DEFAULT_KEEP_ALIVE, 1, UINT32_MAX, 1);
 
498
 
 
499
static MYSQL_SYSVAR_ULONGLONG(next_backup_db_id, my_backup_db_id,
 
500
        PLUGIN_VAR_OPCMDARG,
 
501
        "The next backup ID to use when backing up a PBMS database.",
 
502
        NULL, NULL, 1, 1, UINT64_MAX, 1);
 
503
 
 
504
 
 
505
#ifdef DRIZZLED
 
506
 
 
507
//----------
 
508
static int check_table_list(THD *, struct st_mysql_sys_var *, void *save, drizzle_value *value)
 
509
{
 
510
        char buffer[100];
 
511
        int len = 100;
 
512
        const char *list = value->val_str(value, buffer, &len);
 
513
        TableMatchState state;
 
514
        
 
515
        state = set_match_type(list);
 
516
        if (state == MATCH_ERROR)
 
517
                return 1;
 
518
                
 
519
        char *new_list = strdup(list);
 
520
        if (!new_list)
 
521
                return 1;
 
522
        
 
523
        my_table_list_lock.lock();
 
524
        if (my_table_list && (my_table_list != dflt_my_table_list)) free(my_table_list);
 
525
        my_table_list = new_list;
 
526
        
 
527
        my_table_match = state;
 
528
        my_table_list_lock.unlock();
 
529
 
 
530
   *static_cast<const char**>(save)= my_table_list;
 
531
 
 
532
        return 0;
 
533
}
 
534
 
 
535
//----------
 
536
static void set_table_list(THD *, struct st_mysql_sys_var *, void *var_ptr, CONST_SAVE void *)
 
537
{
 
538
        // Everything was done in check_table_list()
 
539
  *static_cast<const char**>(var_ptr)= my_table_list;
 
540
}
 
541
 
 
542
//----------
 
543
 
 
544
static MYSQL_SYSVAR_STR(watch_tables,
 
545
                           my_table_list,
 
546
                           PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
 
547
                           N_("A comma delimited list of tables to watch of the format: <database>.<table>, ..."),
 
548
                           check_table_list, /* check func */
 
549
                           set_table_list, /* update func */
 
550
                           dflt_my_table_list /* default */);
 
551
 
 
552
static MYSQL_SYSVAR_BOOL(watch_enable,
 
553
                           my_events_enabled,
 
554
                           PLUGIN_VAR_OPCMDARG,
 
555
                           N_("Enable PBMS daemon Insert/Update/Delete event scanning"),
 
556
                           NULL, /* check func */
 
557
                           NULL, /* update func */
 
558
                           true /* default */);
 
559
 
 
560
static MYSQL_SYSVAR_INT(before_insert_position,
 
561
                           my_before_insert_position,
 
562
                           PLUGIN_VAR_OPCMDARG,
 
563
                           N_("Before insert row event observer call position"),
 
564
                           NULL, /* check func */
 
565
                           NULL, /* update func */
 
566
                           1, /* default */
 
567
                           1, /* min */
 
568
                           INT32_MAX -1, /* max */
 
569
                           0 /* blk */);
 
570
 
 
571
static MYSQL_SYSVAR_INT(before_update_position,
 
572
                           my_before_update_position,
 
573
                           PLUGIN_VAR_OPCMDARG,
 
574
                           N_("Before update row event observer call position"),
 
575
                           NULL, /* check func */
 
576
                           NULL, /* update func */
 
577
                           1, /* default */
 
578
                           1, /* min */
 
579
                           INT32_MAX -1, /* max */
 
580
                           0 /* blk */);
 
581
 
 
582
#endif // DRIZZLED
 
583
 
 
584
struct st_mysql_sys_var* pbms_system_variables[] = {
 
585
        MYSQL_SYSVAR(port),
 
586
        MYSQL_SYSVAR(repository_threshold),
 
587
        MYSQL_SYSVAR(temp_log_threshold),
 
588
        MYSQL_SYSVAR(temp_blob_timeout),
 
589
        MYSQL_SYSVAR(garbage_threshold),
 
590
        MYSQL_SYSVAR(http_metadata_headers),
 
591
        MYSQL_SYSVAR(max_keep_alive),
 
592
        MYSQL_SYSVAR(next_backup_db_id),
 
593
        
 
594
#ifdef DRIZZLED
 
595
        MYSQL_SYSVAR(watch_tables),
 
596
        MYSQL_SYSVAR(watch_enable),
 
597
        
 
598
        MYSQL_SYSVAR(before_insert_position),
 
599
        MYSQL_SYSVAR(before_update_position),
 
600
#endif
 
601
  
 
602
        NULL
 
603
};
 
604
 
 
605
 
 
606
 
 
607
 
 
608