summaryrefslogtreecommitdiff
path: root/sql/sql_udf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_udf.cc')
-rw-r--r--sql/sql_udf.cc165
1 files changed, 101 insertions, 64 deletions
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 2906e69fc75..169e0d9e418 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2010, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,8 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* This implements 'user defined functions' */
@@ -33,8 +31,14 @@
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_base.h" // close_mysql_tables
+#include "sql_parse.h" // check_identifier_name
+#include "sql_table.h" // write_bin_log
+#include "records.h" // init_read_record, end_read_record
#include <my_pthread.h>
+#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#ifdef HAVE_DLOPEN
extern "C"
@@ -46,7 +50,7 @@ extern "C"
static bool initialized = 0;
static MEM_ROOT mem;
static HASH udf_hash;
-static rw_lock_t THR_LOCK_udf;
+static mysql_rwlock_t THR_LOCK_udf;
static udf_func *add_udf(LEX_STRING *name, Item_result ret,
@@ -102,6 +106,26 @@ extern "C" uchar* get_hash_key(const uchar *buff, size_t *length,
return (uchar*) udf->name.str;
}
+#ifdef HAVE_PSI_INTERFACE
+static PSI_rwlock_key key_rwlock_THR_LOCK_udf;
+
+static PSI_rwlock_info all_udf_rwlocks[]=
+{
+ { &key_rwlock_THR_LOCK_udf, "THR_LOCK_udf", PSI_FLAG_GLOBAL}
+};
+
+static void init_udf_psi_keys(void)
+{
+ const char* category= "sql";
+ int count;
+
+ if (PSI_server == NULL)
+ return;
+
+ count= array_elements(all_udf_rwlocks);
+ PSI_server->register_rwlock(category, all_udf_rwlocks, count);
+}
+#endif
/*
Read all predeclared functions from mysql.func and accept all that
@@ -121,15 +145,19 @@ void udf_init()
if (initialized)
DBUG_VOID_RETURN;
- my_rwlock_init(&THR_LOCK_udf,NULL);
-
+#ifdef HAVE_PSI_INTERFACE
+ init_udf_psi_keys();
+#endif
+
+ mysql_rwlock_init(key_rwlock_THR_LOCK_udf, &THR_LOCK_udf);
+
init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0);
THD *new_thd = new THD;
if (!new_thd ||
- hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
+ my_hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0))
{
sql_print_error("Can't allocate memory for udf structures");
- hash_free(&udf_hash);
+ my_hash_free(&udf_hash);
free_root(&mem,MYF(0));
delete new_thd;
DBUG_VOID_RETURN;
@@ -137,15 +165,11 @@ void udf_init()
initialized = 1;
new_thd->thread_stack= (char*) &new_thd;
new_thd->store_globals();
- lex_start(new_thd);
new_thd->set_db(db, sizeof(db)-1);
- bzero((uchar*) &tables,sizeof(tables));
- tables.alias= tables.table_name= (char*) "func";
- tables.lock_type = TL_READ;
- tables.db= db;
+ tables.init_one_table(db, sizeof(db)-1, "func", 4, "func", TL_READ);
- if (simple_open_n_lock_tables(new_thd, &tables))
+ if (open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
DBUG_PRINT("error",("Can't open udf table"));
sql_print_error("Can't open the mysql.func table. Please "
@@ -203,6 +227,7 @@ void udf_init()
char dlpath[FN_REFLEN];
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", tmp->dl,
NullS);
+ (void) unpack_filename(dlpath, dlpath);
if (!(dl= dlopen(dlpath, RTLD_NOW)))
{
/* Print warning to log */
@@ -227,10 +252,10 @@ void udf_init()
if (error > 0)
sql_print_error("Got unknown error: %d", my_errno);
end_read_record(&read_record_info);
- new_thd->version--; // Force close to free memory
+ table->m_needs_reopen= TRUE; // Force close to free memory
end:
- close_thread_tables(new_thd);
+ close_mysql_tables(new_thd);
delete new_thd;
/* Remember that we don't have a THD */
my_pthread_setspecific_ptr(THR_THD, 0);
@@ -244,25 +269,25 @@ void udf_free()
DBUG_ENTER("udf_free");
for (uint idx=0 ; idx < udf_hash.records ; idx++)
{
- udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
+ udf_func *udf=(udf_func*) my_hash_element(&udf_hash,idx);
if (udf->dlhandle) // Not closed before
{
/* Mark all versions using the same handler as closed */
for (uint j=idx+1 ; j < udf_hash.records ; j++)
{
- udf_func *tmp=(udf_func*) hash_element(&udf_hash,j);
+ udf_func *tmp=(udf_func*) my_hash_element(&udf_hash,j);
if (udf->dlhandle == tmp->dlhandle)
tmp->dlhandle=0; // Already closed
}
dlclose(udf->dlhandle);
}
}
- hash_free(&udf_hash);
+ my_hash_free(&udf_hash);
free_root(&mem,MYF(0));
if (initialized)
{
initialized= 0;
- rwlock_destroy(&THR_LOCK_udf);
+ mysql_rwlock_destroy(&THR_LOCK_udf);
}
DBUG_VOID_RETURN;
}
@@ -273,7 +298,7 @@ static void del_udf(udf_func *udf)
DBUG_ENTER("del_udf");
if (!--udf->usage_count)
{
- hash_delete(&udf_hash,(uchar*) udf);
+ my_hash_delete(&udf_hash,(uchar*) udf);
using_udf_functions=udf_hash.records != 0;
}
else
@@ -287,7 +312,7 @@ static void del_udf(udf_func *udf)
uint name_length=udf->name.length;
udf->name.str=(char*) "*";
udf->name.length=1;
- hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
+ my_hash_update(&udf_hash,(uchar*) udf,(uchar*) name,name_length);
}
DBUG_VOID_RETURN;
}
@@ -300,19 +325,19 @@ void free_udf(udf_func *udf)
if (!initialized)
DBUG_VOID_RETURN;
- rw_wrlock(&THR_LOCK_udf);
+ mysql_rwlock_wrlock(&THR_LOCK_udf);
if (!--udf->usage_count)
{
/*
We come here when someone has deleted the udf function
while another thread still was using the udf
*/
- hash_delete(&udf_hash,(uchar*) udf);
+ my_hash_delete(&udf_hash,(uchar*) udf);
using_udf_functions=udf_hash.records != 0;
if (!find_udf_dl(udf->dl))
dlclose(udf->dlhandle);
}
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
DBUG_VOID_RETURN;
}
@@ -329,19 +354,19 @@ udf_func *find_udf(const char *name,uint length,bool mark_used)
/* TODO: This should be changed to reader locks someday! */
if (mark_used)
- rw_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
+ mysql_rwlock_wrlock(&THR_LOCK_udf); /* Called during fix_fields */
else
- rw_rdlock(&THR_LOCK_udf); /* Called during parsing */
+ mysql_rwlock_rdlock(&THR_LOCK_udf); /* Called during parsing */
- if ((udf=(udf_func*) hash_search(&udf_hash,(uchar*) name,
- length ? length : (uint) strlen(name))))
+ if ((udf=(udf_func*) my_hash_search(&udf_hash,(uchar*) name,
+ length ? length : (uint) strlen(name))))
{
if (!udf->dlhandle)
udf=0; // Could not be opened
else if (mark_used)
udf->usage_count++;
}
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
DBUG_RETURN(udf);
}
@@ -356,7 +381,7 @@ static void *find_udf_dl(const char *dl)
*/
for (uint idx=0 ; idx < udf_hash.records ; idx++)
{
- udf_func *udf=(udf_func*) hash_element(&udf_hash,idx);
+ udf_func *udf=(udf_func*) my_hash_element(&udf_hash,idx);
if (!strcmp(dl, udf->dl) && udf->dlhandle != NULL)
DBUG_RETURN(udf->dlhandle);
}
@@ -438,11 +463,11 @@ int mysql_create_function(THD *thd,udf_func *udf)
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for CREATE FUNCTION command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- rw_wrlock(&THR_LOCK_udf);
- if ((hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
+ mysql_rwlock_wrlock(&THR_LOCK_udf);
+ if ((my_hash_search(&udf_hash,(uchar*) udf->name.str, udf->name.length)))
{
my_error(ER_UDF_EXISTS, MYF(0), udf->name.str);
goto err;
@@ -451,6 +476,8 @@ int mysql_create_function(THD *thd,udf_func *udf)
{
char dlpath[FN_REFLEN];
strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", udf->dl, NullS);
+ (void) unpack_filename(dlpath, dlpath);
+
if (!(dl = dlopen(dlpath, RTLD_NOW)))
{
DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
@@ -483,11 +510,9 @@ int mysql_create_function(THD *thd,udf_func *udf)
/* create entry in mysql.func table */
- bzero((char*) &tables,sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "func";
+ tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE);
/* Allow creation of functions even if we can't open func table */
- if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
+ if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
goto err;
table->use_all_columns();
restore_record(table, s->default_values); // Default values for fields
@@ -504,25 +529,31 @@ int mysql_create_function(THD *thd,udf_func *udf)
del_udf(u_d);
goto err;
}
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
/* Binlog the create function. */
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(0);
err:
if (new_dl)
dlclose(dl);
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
@@ -550,12 +581,12 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
Turn off row binlogging of this statement and use statement-based
so that all supporting tables are updated for DROP FUNCTION command.
*/
- save_binlog_row_based= thd->current_stmt_binlog_row_based;
- thd->clear_current_stmt_binlog_row_based();
+ if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
+ thd->clear_current_stmt_binlog_format_row();
- rw_wrlock(&THR_LOCK_udf);
- if (!(udf=(udf_func*) hash_search(&udf_hash,(uchar*) udf_name->str,
- (uint) udf_name->length)))
+ mysql_rwlock_wrlock(&THR_LOCK_udf);
+ if (!(udf=(udf_func*) my_hash_search(&udf_hash,(uchar*) udf_name->str,
+ (uint) udf_name->length)))
{
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), udf_name->str);
goto err;
@@ -570,10 +601,9 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
if (udf->dlhandle && !find_udf_dl(udf->dl))
dlclose(udf->dlhandle);
- bzero((char*) &tables,sizeof(tables));
- tables.db=(char*) "mysql";
- tables.table_name= tables.alias= (char*) "func";
- if (!(table = open_ltable(thd, &tables, TL_WRITE, 0)))
+ tables.init_one_table("mysql", 5, "func", 4, "func", TL_WRITE);
+
+ if (!(table = open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
goto err;
table->use_all_columns();
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
@@ -586,24 +616,31 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
if ((error = table->file->ha_delete_row(table->record[0])))
table->file->print_error(error, MYF(0));
}
- close_thread_tables(thd);
-
- rw_unlock(&THR_LOCK_udf);
+ mysql_rwlock_unlock(&THR_LOCK_udf);
- /* Binlog the drop function. */
+ /*
+ Binlog the drop function. Keep the table open and locked
+ while binlogging, to avoid binlog inconsistency.
+ */
if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
{
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(0);
- err:
- rw_unlock(&THR_LOCK_udf);
+err:
+ mysql_rwlock_unlock(&THR_LOCK_udf);
/* Restore the state of binlog format */
- thd->current_stmt_binlog_row_based= save_binlog_row_based;
+ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ if (save_binlog_row_based)
+ thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(1);
}