1/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16
17#ifdef USE_PRAGMA_IMPLEMENTATION
18#pragma implementation // gcc: Class implementation
19#endif
20
21#define MYSQL_SERVER 1
22#include <my_global.h>
23#include "sql_priv.h"
24#include "unireg.h"
25#include "ha_blackhole.h"
26#include "sql_class.h" // THD, SYSTEM_THREAD_SLAVE_SQL
27
28/* Static declarations for handlerton */
29
30static handler *blackhole_create_handler(handlerton *hton,
31 TABLE_SHARE *table,
32 MEM_ROOT *mem_root)
33{
34 return new (mem_root) ha_blackhole(hton, table);
35}
36
37
38/* Static declarations for shared structures */
39
40static mysql_mutex_t blackhole_mutex;
41static HASH blackhole_open_tables;
42
43static st_blackhole_share *get_share(const char *table_name);
44static void free_share(st_blackhole_share *share);
45
46/*****************************************************************************
47** BLACKHOLE tables
48*****************************************************************************/
49
50ha_blackhole::ha_blackhole(handlerton *hton,
51 TABLE_SHARE *table_arg)
52 :handler(hton, table_arg)
53{}
54
55
56int ha_blackhole::open(const char *name, int mode, uint test_if_locked)
57{
58 DBUG_ENTER("ha_blackhole::open");
59
60 if (!(share= get_share(name)))
61 DBUG_RETURN(HA_ERR_OUT_OF_MEM);
62
63 thr_lock_data_init(&share->lock, &lock, NULL);
64 DBUG_RETURN(0);
65}
66
67int ha_blackhole::close(void)
68{
69 DBUG_ENTER("ha_blackhole::close");
70 free_share(share);
71 DBUG_RETURN(0);
72}
73
74int ha_blackhole::create(const char *name, TABLE *table_arg,
75 HA_CREATE_INFO *create_info)
76{
77 DBUG_ENTER("ha_blackhole::create");
78 DBUG_RETURN(0);
79}
80
81/*
82 Intended to support partitioning.
83 Allows a particular partition to be truncated.
84*/
85int ha_blackhole::truncate()
86{
87 DBUG_ENTER("ha_blackhole::truncate");
88 DBUG_RETURN(0);
89}
90
91const char *ha_blackhole::index_type(uint key_number)
92{
93 DBUG_ENTER("ha_blackhole::index_type");
94 DBUG_RETURN((table_share->key_info[key_number].flags & HA_FULLTEXT) ?
95 "FULLTEXT" :
96 (table_share->key_info[key_number].flags & HA_SPATIAL) ?
97 "SPATIAL" :
98 (table_share->key_info[key_number].algorithm ==
99 HA_KEY_ALG_RTREE) ? "RTREE" : "BTREE");
100}
101
102int ha_blackhole::write_row(uchar * buf)
103{
104 DBUG_ENTER("ha_blackhole::write_row");
105 DBUG_RETURN(table->next_number_field ? update_auto_increment() : 0);
106}
107
108int ha_blackhole::update_row(const uchar *old_data, const uchar *new_data)
109{
110 DBUG_ENTER("ha_blackhole::update_row");
111 THD *thd= ha_thd();
112 if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL)
113 DBUG_RETURN(0);
114 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
115}
116
117int ha_blackhole::delete_row(const uchar *buf)
118{
119 DBUG_ENTER("ha_blackhole::delete_row");
120 THD *thd= ha_thd();
121 if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL)
122 DBUG_RETURN(0);
123 DBUG_RETURN(HA_ERR_WRONG_COMMAND);
124}
125
126int ha_blackhole::rnd_init(bool scan)
127{
128 DBUG_ENTER("ha_blackhole::rnd_init");
129 DBUG_RETURN(0);
130}
131
132
133int ha_blackhole::rnd_next(uchar *buf)
134{
135 int rc;
136 DBUG_ENTER("ha_blackhole::rnd_next");
137 THD *thd= ha_thd();
138 if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL)
139 rc= 0;
140 else
141 rc= HA_ERR_END_OF_FILE;
142 DBUG_RETURN(rc);
143}
144
145
146int ha_blackhole::rnd_pos(uchar * buf, uchar *pos)
147{
148 DBUG_ENTER("ha_blackhole::rnd_pos");
149 DBUG_ASSERT(0);
150 DBUG_RETURN(0);
151}
152
153
154void ha_blackhole::position(const uchar *record)
155{
156 DBUG_ENTER("ha_blackhole::position");
157 DBUG_ASSERT(0);
158 DBUG_VOID_RETURN;
159}
160
161
162int ha_blackhole::info(uint flag)
163{
164 DBUG_ENTER("ha_blackhole::info");
165
166 bzero((char*) &stats, sizeof(stats));
167 if (flag & HA_STATUS_AUTO)
168 stats.auto_increment_value= 1;
169 DBUG_RETURN(0);
170}
171
172int ha_blackhole::external_lock(THD *thd, int lock_type)
173{
174 DBUG_ENTER("ha_blackhole::external_lock");
175 DBUG_RETURN(0);
176}
177
178
179THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
180 THR_LOCK_DATA **to,
181 enum thr_lock_type lock_type)
182{
183 DBUG_ENTER("ha_blackhole::store_lock");
184 if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
185 {
186 /*
187 Here is where we get into the guts of a row level lock.
188 If TL_UNLOCK is set
189 If we are not doing a LOCK TABLE or DISCARD/IMPORT
190 TABLESPACE, then allow multiple writers
191 */
192
193 if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
194 lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
195 && !thd_tablespace_op(thd))
196 lock_type = TL_WRITE_ALLOW_WRITE;
197
198 /*
199 In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
200 MySQL would use the lock TL_READ_NO_INSERT on t2, and that
201 would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
202 to t2. Convert the lock to a normal read lock to allow
203 concurrent inserts to t2.
204 */
205
206 if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd))
207 lock_type = TL_READ;
208
209 lock.type= lock_type;
210 }
211 *to++= &lock;
212 DBUG_RETURN(to);
213}
214
215
216int ha_blackhole::index_read_map(uchar * buf, const uchar * key,
217 key_part_map keypart_map,
218 enum ha_rkey_function find_flag)
219{
220 int rc;
221 DBUG_ENTER("ha_blackhole::index_read");
222 THD *thd= ha_thd();
223 if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL)
224 rc= 0;
225 else
226 rc= HA_ERR_END_OF_FILE;
227 DBUG_RETURN(rc);
228}
229
230
231int ha_blackhole::index_read_idx_map(uchar * buf, uint idx, const uchar * key,
232 key_part_map keypart_map,
233 enum ha_rkey_function find_flag)
234{
235 int rc;
236 DBUG_ENTER("ha_blackhole::index_read_idx");
237 THD *thd= ha_thd();
238 if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL)
239 rc= 0;
240 else
241 rc= HA_ERR_END_OF_FILE;
242 DBUG_RETURN(rc);
243}
244
245
246int ha_blackhole::index_read_last_map(uchar * buf, const uchar * key,
247 key_part_map keypart_map)
248{
249 int rc;
250 DBUG_ENTER("ha_blackhole::index_read_last");
251 THD *thd= ha_thd();
252 if (thd->system_thread == SYSTEM_THREAD_SLAVE_SQL && thd->query() == NULL)
253 rc= 0;
254 else
255 rc= HA_ERR_END_OF_FILE;
256 DBUG_RETURN(rc);
257}
258
259
260int ha_blackhole::index_next(uchar * buf)
261{
262 int rc;
263 DBUG_ENTER("ha_blackhole::index_next");
264 rc= HA_ERR_END_OF_FILE;
265 DBUG_RETURN(rc);
266}
267
268
269int ha_blackhole::index_prev(uchar * buf)
270{
271 int rc;
272 DBUG_ENTER("ha_blackhole::index_prev");
273 rc= HA_ERR_END_OF_FILE;
274 DBUG_RETURN(rc);
275}
276
277
278int ha_blackhole::index_first(uchar * buf)
279{
280 int rc;
281 DBUG_ENTER("ha_blackhole::index_first");
282 rc= HA_ERR_END_OF_FILE;
283 DBUG_RETURN(rc);
284}
285
286
287int ha_blackhole::index_last(uchar * buf)
288{
289 int rc;
290 DBUG_ENTER("ha_blackhole::index_last");
291 rc= HA_ERR_END_OF_FILE;
292 DBUG_RETURN(rc);
293}
294
295
296static st_blackhole_share *get_share(const char *table_name)
297{
298 st_blackhole_share *share;
299 uint length;
300
301 length= (uint) strlen(table_name);
302 mysql_mutex_lock(&blackhole_mutex);
303
304 if (!(share= (st_blackhole_share*)
305 my_hash_search(&blackhole_open_tables,
306 (uchar*) table_name, length)))
307 {
308 if (!(share= (st_blackhole_share*) my_malloc(sizeof(st_blackhole_share) +
309 length,
310 MYF(MY_WME | MY_ZEROFILL))))
311 goto error;
312
313 share->table_name_length= length;
314 strmov(share->table_name, table_name);
315
316 if (my_hash_insert(&blackhole_open_tables, (uchar*) share))
317 {
318 my_free(share);
319 share= NULL;
320 goto error;
321 }
322
323 thr_lock_init(&share->lock);
324 }
325 share->use_count++;
326
327error:
328 mysql_mutex_unlock(&blackhole_mutex);
329 return share;
330}
331
332static void free_share(st_blackhole_share *share)
333{
334 mysql_mutex_lock(&blackhole_mutex);
335 if (!--share->use_count)
336 my_hash_delete(&blackhole_open_tables, (uchar*) share);
337 mysql_mutex_unlock(&blackhole_mutex);
338}
339
340static void blackhole_free_key(st_blackhole_share *share)
341{
342 thr_lock_delete(&share->lock);
343 my_free(share);
344}
345
346static uchar* blackhole_get_key(st_blackhole_share *share, size_t *length,
347 my_bool not_used __attribute__((unused)))
348{
349 *length= share->table_name_length;
350 return (uchar*) share->table_name;
351}
352
353#ifdef HAVE_PSI_INTERFACE
354static PSI_mutex_key bh_key_mutex_blackhole;
355
356static PSI_mutex_info all_blackhole_mutexes[]=
357{
358 { &bh_key_mutex_blackhole, "blackhole", PSI_FLAG_GLOBAL}
359};
360
361void init_blackhole_psi_keys()
362{
363 const char* category= "blackhole";
364 int count;
365
366 if (PSI_server == NULL)
367 return;
368
369 count= array_elements(all_blackhole_mutexes);
370 PSI_server->register_mutex(category, all_blackhole_mutexes, count);
371}
372#endif
373
374static int blackhole_init(void *p)
375{
376 handlerton *blackhole_hton;
377
378#ifdef HAVE_PSI_INTERFACE
379 init_blackhole_psi_keys();
380#endif
381
382 blackhole_hton= (handlerton *)p;
383 blackhole_hton->state= SHOW_OPTION_YES;
384 blackhole_hton->db_type= DB_TYPE_BLACKHOLE_DB;
385 blackhole_hton->create= blackhole_create_handler;
386 blackhole_hton->flags= HTON_CAN_RECREATE;
387
388 mysql_mutex_init(bh_key_mutex_blackhole,
389 &blackhole_mutex, MY_MUTEX_INIT_FAST);
390 (void) my_hash_init(&blackhole_open_tables, system_charset_info,32,0,0,
391 (my_hash_get_key) blackhole_get_key,
392 (my_hash_free_key) blackhole_free_key, 0);
393
394 return 0;
395}
396
397static int blackhole_fini(void *p)
398{
399 my_hash_free(&blackhole_open_tables);
400 mysql_mutex_destroy(&blackhole_mutex);
401
402 return 0;
403}
404
405struct st_mysql_storage_engine blackhole_storage_engine=
406{ MYSQL_HANDLERTON_INTERFACE_VERSION };
407
408mysql_declare_plugin(blackhole)
409{
410 MYSQL_STORAGE_ENGINE_PLUGIN,
411 &blackhole_storage_engine,
412 "BLACKHOLE",
413 "MySQL AB",
414 "/dev/null storage engine (anything you write to it disappears)",
415 PLUGIN_LICENSE_GPL,
416 blackhole_init, /* Plugin Init */
417 blackhole_fini, /* Plugin Deinit */
418 0x0100 /* 1.0 */,
419 NULL, /* status variables */
420 NULL, /* system variables */
421 NULL, /* config options */
422 0, /* flags */
423}
424mysql_declare_plugin_end;
425maria_declare_plugin(blackhole)
426{
427 MYSQL_STORAGE_ENGINE_PLUGIN,
428 &blackhole_storage_engine,
429 "BLACKHOLE",
430 "MySQL AB",
431 "/dev/null storage engine (anything you write to it disappears)",
432 PLUGIN_LICENSE_GPL,
433 blackhole_init, /* Plugin Init */
434 blackhole_fini, /* Plugin Deinit */
435 0x0100 /* 1.0 */,
436 NULL, /* status variables */
437 NULL, /* system variables */
438 "1.0", /* string version */
439 MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
440}
441maria_declare_plugin_end;
442