List:Commits« Previous MessageNext Message »
From:antony Date:November 29 2007 10:40pm
Subject:bk commit into 6.0 tree (acurtis:1.2699) WL#3771
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of antony. When antony does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-11-29 14:40:36-08:00, acurtis@stripped +34 -0
  WL#3771 - Plugable Audit Interface
    First commit for review
    Have run default tests with/without plugin:
    mysql-test-run.pl --mysqld=--plugin-dir=<path to plugin>
                      --mysqld=--plugin-load=adt_null.so

  include/Makefile.am@stripped, 2007-11-29 14:40:15-08:00, acurtis@stripped +2 -1
    add new source files: mysql/ftparser.h mysql/audit.h

  include/myisam.h@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +1 -1
    change include mysql/plugin.h -> mysql/ftparser.h

  include/mysql/audit.h@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +126 -0
    New BitKeeper file ``include/mysql/audit.h''

  include/mysql/audit.h@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  include/mysql/ftparser.h@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +211 -0
    New BitKeeper file ``include/mysql/ftparser.h''

  include/mysql/ftparser.h@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  include/mysql/plugin.h@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +26 -202
    New plugin type: MYSQL_AUDIT_PLUGIN
    Allow declaration of Opaque thread variables.
    New flag so that thread variables have no user-modifiable GLOBAL 
    value - requested by Kevin Lewis.
    Move MYSQL_FTPARSER_PLUGIN declarations into mysql/ftparser.h

  libmysqld/Makefile.am@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +1 -1
    Add new file to build: sql_audit.cc

  plugin/audit_null/AUTHORS@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +1 -0
    New BitKeeper file ``plugin/audit_null/AUTHORS''

  plugin/audit_null/AUTHORS@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +0 -0

  plugin/audit_null/ChangeLog@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +1 -0
    New BitKeeper file ``plugin/audit_null/ChangeLog''

  plugin/audit_null/ChangeLog@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +0 -0

  plugin/audit_null/Makefile.am@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +27 -0
    New BitKeeper file ``plugin/audit_null/Makefile.am''

  plugin/audit_null/Makefile.am@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +0 -0

  plugin/audit_null/NEWS@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +1 -0
    New BitKeeper file ``plugin/audit_null/NEWS''

  plugin/audit_null/NEWS@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  plugin/audit_null/README@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +1 -0
    New BitKeeper file ``plugin/audit_null/README''

  plugin/audit_null/README@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  plugin/audit_null/audit_null.c@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +142 -0
    New BitKeeper file ``plugin/audit_null/audit_null.c''

  plugin/audit_null/audit_null.c@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  plugin/audit_null/configure.in@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +9 -0
    New BitKeeper file ``plugin/audit_null/configure.in''

  plugin/audit_null/configure.in@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  plugin/audit_null/plug.in@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +3 -0
    New BitKeeper file ``plugin/audit_null/plug.in''

  plugin/audit_null/plug.in@stripped, 2007-11-29 14:40:19-08:00, acurtis@stripped +0 -0

  plugin/fulltext/plugin_example.c@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +1 -1
    change include mysql/plugin.h -> mysql/ftparser.h

  sql/Makefile.am@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +2 -2
    add new files to build: sql_audit.h sql_audit.cc

  sql/event_queue.cc@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +8 -0
    Release Audit resources before waiting

  sql/ha_ndbcluster_binlog.cc@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +25 -0
    Release Audit resources before waiting

  sql/log.cc@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +41 -2
    add locations to audit

  sql/mysqld.cc@stripped, 2007-11-29 14:40:16-08:00, acurtis@stripped +7 -0
    initialize/finalize audit globals

  sql/protocol.cc@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +13 -0
    add locations to audit

  sql/scheduler.cc@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +5 -0
    release audit resources before waiting

  sql/slave.cc@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +18 -0
    release audit resources before waiting

  sql/sql_acl.cc@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +343 -91
    add locations to audit

  sql/sql_audit.cc@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +502 -0
    New BitKeeper file ``sql/sql_audit.cc''

  sql/sql_audit.cc@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +0 -0

  sql/sql_audit.h@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +95 -0
    New BitKeeper file ``sql/sql_audit.h''

  sql/sql_audit.h@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +0 -0

  sql/sql_builtin.cc.in@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +1 -0
    include my_global.h

  sql/sql_class.cc@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +4 -0
    initialize/finalize audit variables

  sql/sql_class.h@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +4 -0
    Audit variables in THD

  sql/sql_connect.cc@stripped, 2007-11-29 14:40:17-08:00, acurtis@stripped +12 -0
    add locations to audit

  sql/sql_insert.cc@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +3 -0
    release audit resources before waiting

  sql/sql_plugin.cc@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +107 -44
    Handle new plugin type: MYSQL_AUDIT_PLUGIN
    Handle opaque thread variables.
    Handle PLUGIN_VAR_NOGLOBAL flag.
    Correctly handle --plugin-load=xxx without crashing.

  storage/myisam/ftdefs.h@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +1 -1
    change include mysql/plugin.h -> mysql/ftparser.h

  storage/myisam/ha_myisam.cc@stripped, 2007-11-29 14:40:18-08:00, acurtis@stripped +1 -1
    change include mysql/plugin.h -> mysql/ftparser.h

diff -Nrup a/include/Makefile.am b/include/Makefile.am
--- a/include/Makefile.am	2007-10-09 12:42:15 -07:00
+++ b/include/Makefile.am	2007-11-29 14:40:15 -08:00
@@ -18,7 +18,8 @@
 BUILT_SOURCES =		$(HEADERS_GEN) link_sources
 HEADERS_GEN =		mysql_version.h my_config.h
 HEADERS_ABI =		mysql.h mysql_com.h mysql_time.h \
-			my_list.h my_alloc.h typelib.h mysql/plugin.h
+			my_list.h my_alloc.h typelib.h mysql/plugin.h \
+			mysql/ftparser.h mysql/audit.h
 pkginclude_HEADERS =	$(HEADERS_ABI) my_dbug.h m_string.h my_sys.h \
 			my_xml.h mysql_embed.h \
 		  	my_pthread.h my_no_pthread.h \
diff -Nrup a/include/myisam.h b/include/myisam.h
--- a/include/myisam.h	2007-10-22 04:43:27 -07:00
+++ b/include/myisam.h	2007-11-29 14:40:16 -08:00
@@ -31,7 +31,7 @@ extern "C" {
 #include "keycache.h"
 #endif
 #include "my_handler.h"
-#include <mysql/plugin.h>
+#include <mysql/ftparser.h>
 
 /*
   There is a hard limit for the maximum number of keys as there are only
diff -Nrup a/include/mysql/audit.h b/include/mysql/audit.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/mysql/audit.h	2007-11-29 14:40:19 -08:00
@@ -0,0 +1,126 @@
+/* Copyright (C) 2007 MySQL AB
+
+   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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef _my_audit_h
+#define _my_audit_h
+
+/*************************************************************************
+  API for Audit plugin. (MYSQL_AUDIT_PLUGIN)
+*/
+
+#include "plugin.h"
+
+#define MYSQL_AUDIT_INTERFACE_VERSION 0x0100
+
+
+struct mysql_event
+{
+  int event_class;
+};
+
+#ifdef __cplusplus
+#define DECLARE_AUDIT_EVENT_DATA(name) \
+struct mysql_event_ ## name :public mysql_event {
+#else
+#define DECLARE_AUDIT_EVENT_DATA(name) \
+struct mysql_event_ ## name {          \
+  int event_class;
+#endif
+#define END_DECLARE_AUDIT_EVENT_DATA }
+
+
+/*************************************************************************
+  AUDIT CLASS : GENERAL
+*/
+
+#define MYSQL_AUDIT_GENERAL_CLASS 0
+#define MYSQL_AUDIT_GENERAL_CLASSMASK1 (1 << MYSQL_AUDIT_GENERAL_CLASS)
+#define MYSQL_AUDIT_GENERAL_LOG 0
+#define MYSQL_AUDIT_GENERAL_ERROR 1
+#define MYSQL_AUDIT_GENERAL_RESULT 2
+#define MYSQL_AUDIT_GENERAL_CONSOLE 3
+DECLARE_AUDIT_EVENT_DATA(general)
+  int general_error_code;
+  unsigned long general_thread_id;
+  time_t general_time;
+  const char *general_user;
+  unsigned int general_user_length;
+  const char *general_command;
+  unsigned int general_command_length;
+  const char *general_query;
+  unsigned int general_query_length;
+  struct charset_info_st *general_charset;
+  unsigned long long general_rows;
+END_DECLARE_AUDIT_EVENT_DATA;
+
+
+/*************************************************************************
+  AUDIT CLASS : SECURITY
+*/
+
+#define MYSQL_AUDIT_SECURITY_CLASS 1
+#define MYSQL_AUDIT_SECURITY_CLASSMASK1 (1 << MYSQL_AUDIT_SECURITY_CLASS)
+#define MYSQL_AUDIT_SECURITY_RELOAD 0
+#define MYSQL_AUDIT_SECURITY_AUTHENTICATE 1
+#define MYSQL_AUDIT_SECURITY_CONNECT 2
+#define MYSQL_AUDIT_SECURITY_DISCONNECT 3
+#define MYSQL_AUDIT_SECURITY_CHECK_ENTER 4
+#define MYSQL_AUDIT_SECURITY_CHECK_LEAVE 5
+#define MYSQL_AUDIT_SECURITY_GRANT 6
+#define MYSQL_AUDIT_SECURITY_REVOKE 7
+DECLARE_AUDIT_EVENT_DATA(security)
+  int security_error_code;
+  unsigned long security_thread_id;
+  const char *security_host;
+  unsigned int security_host_length;  
+  const char *security_user;
+  unsigned int security_user_length;
+  const char *security_priv_user;
+  unsigned int security_priv_user_length;
+  const char *security_ip;
+  unsigned int security_ip_length;
+  const char *security_host_or_ip;
+  unsigned int security_host_or_ip_length;
+  unsigned long security_global_access;
+  unsigned long security_schema_access;
+
+  const char *security_type;
+  unsigned int security_type_length;
+  const char *security_schema;
+  unsigned int security_schema_length;
+  const char *security_object;
+  unsigned int security_object_length;
+  const char *security_element;
+  unsigned int security_element_length;
+
+  unsigned long security_object_rights;
+END_DECLARE_AUDIT_EVENT_DATA;
+
+
+/*************************************************************************
+  Here we define the descriptor structure, that is referred from
+  st_mysql_plugin.
+*/
+
+struct st_mysql_audit
+{
+  int interface_version;
+  const unsigned long long *class_mask;
+  void (*release_thd)(MYSQL_THD);
+  void (*event_notify)(MYSQL_THD, const struct mysql_event *);
+};
+
+
+#endif
diff -Nrup a/include/mysql/ftparser.h b/include/mysql/ftparser.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/include/mysql/ftparser.h	2007-11-29 14:40:19 -08:00
@@ -0,0 +1,211 @@
+/* Copyright (C) 2005 MySQL AB
+
+   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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef _my_ftparser_h
+#define _my_ftparser_h
+
+/*************************************************************************
+  API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN)
+*/
+
+#include "plugin.h"
+
+#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100
+
+/* Parsing modes. Set in  MYSQL_FTPARSER_PARAM::mode */
+enum enum_ftparser_mode
+{
+/*
+  Fast and simple mode.  This mode is used for indexing, and natural
+  language queries.
+
+  The parser is expected to return only those words that go into the
+  index. Stopwords or too short/long words should not be returned. The
+  'boolean_info' argument of mysql_add_word() does not have to be set.
+*/
+  MYSQL_FTPARSER_SIMPLE_MODE= 0,
+
+/*
+  Parse with stopwords mode.  This mode is used in boolean searches for
+  "phrase matching."
+
+  The parser is not allowed to ignore words in this mode.  Every word
+  should be returned, including stopwords and words that are too short
+  or long.  The 'boolean_info' argument of mysql_add_word() does not
+  have to be set.
+*/
+  MYSQL_FTPARSER_WITH_STOPWORDS= 1,
+
+/*
+  Parse in boolean mode.  This mode is used to parse a boolean query string.
+
+  The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO
+  structure in the 'boolean_info' argument to mysql_add_word().
+  Usually that means that the parser should recognize boolean operators
+  in the parsing stream and set appropriate fields in
+  MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly.  As for
+  MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored.
+  Instead, use FT_TOKEN_STOPWORD for the token type of such a word.
+*/
+  MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2
+};
+
+/*
+  Token types for boolean mode searching (used for the type member of
+  MYSQL_FTPARSER_BOOLEAN_INFO struct)
+
+  FT_TOKEN_EOF: End of data.
+  FT_TOKEN_WORD: Regular word.
+  FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression).
+  FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression).
+  FT_TOKEN_STOPWORD: Stopword.
+*/
+
+enum enum_ft_token_type
+{
+  FT_TOKEN_EOF= 0,
+  FT_TOKEN_WORD= 1,
+  FT_TOKEN_LEFT_PAREN= 2,
+  FT_TOKEN_RIGHT_PAREN= 3,
+  FT_TOKEN_STOPWORD= 4
+};
+
+/*
+  This structure is used in boolean search mode only. It conveys
+  boolean-mode metadata to the MySQL search engine for every word in
+  the search query. A valid instance of this structure must be filled
+  in by the plugin parser and passed as an argument in the call to
+  mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM
+  structure) when a query is parsed in boolean mode.
+
+  type: The token type.  Should be one of the enum_ft_token_type values.
+
+  yesno: Whether the word must be present for a match to occur:
+    >0 Must be present
+    <0 Must not be present
+    0  Neither; the word is optional but its presence increases the relevance
+  With the default settings of the ft_boolean_syntax system variable,
+  >0 corresponds to the '+' operator, <0 corrresponds to the '-' operator,
+  and 0 means neither operator was used.
+
+  weight_adjust: A weighting factor that determines how much a match
+  for the word counts.  Positive values increase, negative - decrease the
+  relative word's importance in the query.
+
+  wasign: The sign of the word's weight in the query. If it's non-negative
+  the match for the word will increase document relevance, if it's
+  negative - decrease (the word becomes a "noise word", the less of it the
+  better).
+
+  trunc: Corresponds to the '*' operator in the default setting of the
+  ft_boolean_syntax system variable.
+*/
+
+typedef struct st_mysql_ftparser_boolean_info
+{
+  enum enum_ft_token_type type;
+  int yesno;
+  int weight_adjust;
+  char wasign;
+  char trunc;
+  /* These are parser state and must be removed. */
+  char prev;
+  char *quot;
+} MYSQL_FTPARSER_BOOLEAN_INFO;
+
+/*
+  The following flag means that buffer with a string (document, word)
+  may be overwritten by the caller before the end of the parsing (that is
+  before st_mysql_ftparser::deinit() call). If one needs the string
+  to survive between two successive calls of the parsing function, she
+  needs to save a copy of it. The flag may be set by MySQL before calling
+  st_mysql_ftparser::parse(), or it may be set by a plugin before calling
+  st_mysql_ftparser_param::mysql_parse() or
+  st_mysql_ftparser_param::mysql_add_word().
+*/
+#define MYSQL_FTFLAGS_NEED_COPY 1
+
+/*
+  An argument of the full-text parser plugin. This structure is
+  filled in by MySQL server and passed to the parsing function of the
+  plugin as an in/out parameter.
+
+  mysql_parse: A pointer to the built-in parser implementation of the
+  server. It's set by the server and can be used by the parser plugin
+  to invoke the MySQL default parser.  If plugin's role is to extract
+  textual data from .doc, .pdf or .xml content, it might extract
+  plaintext from the content, and then pass the text to the default
+  MySQL parser to be parsed.
+
+  mysql_add_word: A server callback to add a new word.  When parsing
+  a document, the server sets this to point at a function that adds
+  the word to MySQL full-text index.  When parsing a search query,
+  this function will add the new word to the list of words to search
+  for.  The boolean_info argument can be NULL for all cases except
+  when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO.
+
+  ftparser_state: A generic pointer. The plugin can set it to point
+  to information to be used internally for its own purposes.
+
+  mysql_ftparam: This is set by the server.  It is used by MySQL functions
+  called via mysql_parse() and mysql_add_word() callback.  The plugin
+  should not modify it.
+
+  cs: Information about the character set of the document or query string.
+
+  doc: A pointer to the document or query string to be parsed.
+
+  length: Length of the document or query string, in bytes.
+
+  flags: See MYSQL_FTFLAGS_* constants above.
+
+  mode: The parsing mode.  With boolean operators, with stopwords, or
+  nothing.  See  enum_ftparser_mode above.
+*/
+
+typedef struct st_mysql_ftparser_param
+{
+  int (*mysql_parse)(struct st_mysql_ftparser_param *,
+                     char *doc, int doc_len);
+  int (*mysql_add_word)(struct st_mysql_ftparser_param *,
+                        char *word, int word_len,
+                        MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
+  void *ftparser_state;
+  void *mysql_ftparam;
+  struct charset_info_st *cs;
+  char *doc;
+  int length;
+  int flags;
+  enum enum_ftparser_mode mode;
+} MYSQL_FTPARSER_PARAM;
+
+
+/*
+  Full-text parser descriptor.
+
+  interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION.
+  The parsing, initialization, and deinitialization functions are
+  invoked per SQL statement for which the parser is used.
+*/
+
+struct st_mysql_ftparser
+{
+  int interface_version;
+  int (*parse)(MYSQL_FTPARSER_PARAM *param);
+  int (*init)(MYSQL_FTPARSER_PARAM *param);
+  int (*deinit)(MYSQL_FTPARSER_PARAM *param);
+};
+
+#endif
diff -Nrup a/include/mysql/plugin.h b/include/mysql/plugin.h
--- a/include/mysql/plugin.h	2007-08-30 23:19:49 -07:00
+++ b/include/mysql/plugin.h	2007-11-29 14:40:16 -08:00
@@ -65,7 +65,8 @@ typedef struct st_mysql_xid MYSQL_XID;
 #define MYSQL_FTPARSER_PLUGIN        2  /* Full-text parser plugin      */
 #define MYSQL_DAEMON_PLUGIN          3  /* The daemon/raw plugin type */
 #define MYSQL_INFORMATION_SCHEMA_PLUGIN  4  /* The I_S plugin type */
-#define MYSQL_MAX_PLUGIN_TYPE_NUM    5  /* The number of plugin types   */
+#define MYSQL_AUDIT_PLUGIN           5  /* The Audit plugin type        */
+#define MYSQL_MAX_PLUGIN_TYPE_NUM    6  /* The number of plugin types   */
 
 /* We use the following strings to define licenses for plugins */
 #define PLUGIN_LICENSE_PROPRIETARY 0
@@ -135,6 +136,7 @@ typedef int (*mysql_show_var_func)(MYSQL
 #define PLUGIN_VAR_STR          0x0005
 #define PLUGIN_VAR_ENUM         0x0006
 #define PLUGIN_VAR_SET          0x0007
+#define PLUGIN_VAR_OPAQUE       0x0008
 #define PLUGIN_VAR_UNSIGNED     0x0080
 #define PLUGIN_VAR_THDLOCAL     0x0100 /* Variable is per-connection */
 #define PLUGIN_VAR_READONLY     0x0200 /* Server variable is read only */
@@ -143,6 +145,7 @@ typedef int (*mysql_show_var_func)(MYSQL
 #define PLUGIN_VAR_NOCMDARG     0x1000 /* No argument for cmd line */
 #define PLUGIN_VAR_RQCMDARG     0x0000 /* Argument required for cmd line */
 #define PLUGIN_VAR_OPCMDARG     0x2000 /* Argument optional for cmd line */
+#define PLUGIN_VAR_NOGLOBAL     0x4000 /* per-connection has no global */
 #define PLUGIN_VAR_MEMALLOC     0x8000 /* String needs memory allocated */
 
 struct st_mysql_sys_var;
@@ -367,6 +370,12 @@ DECLARE_MYSQL_THDVAR_TYPELIB(name, unsig
   PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \
   #name, comment, check, update, -1, def, NULL, typelib }
 
+#define MYSQL_THDVAR_OPAQUE(name, type) \
+DECLARE_MYSQL_THDVAR_BASIC(name, __typeof__ (type *)) = { \
+  PLUGIN_VAR_OPAQUE | PLUGIN_VAR_THDLOCAL | \
+  PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT, #name, \
+  NULL, NULL, NULL, -1, NULL, NULL }
+
 /* accessor macros */
 
 #define SYSVAR(name) \
@@ -397,208 +406,43 @@ struct st_mysql_plugin
   void * __reserved1;   /* reserved for dependency checking             */
 };
 
-/*************************************************************************
-  API for Full-text parser plugin. (MYSQL_FTPARSER_PLUGIN)
-*/
-
-#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0100
-
-/* Parsing modes. Set in  MYSQL_FTPARSER_PARAM::mode */
-enum enum_ftparser_mode
-{
-/*
-  Fast and simple mode.  This mode is used for indexing, and natural
-  language queries.
-
-  The parser is expected to return only those words that go into the
-  index. Stopwords or too short/long words should not be returned. The
-  'boolean_info' argument of mysql_add_word() does not have to be set.
-*/
-  MYSQL_FTPARSER_SIMPLE_MODE= 0,
-
-/*
-  Parse with stopwords mode.  This mode is used in boolean searches for
-  "phrase matching."
 
-  The parser is not allowed to ignore words in this mode.  Every word
-  should be returned, including stopwords and words that are too short
-  or long.  The 'boolean_info' argument of mysql_add_word() does not
-  have to be set.
+/*************************************************************************
+  API for Daemon/raw plugin. (MYSQL_DAEMON_PLUGIN)
 */
-  MYSQL_FTPARSER_WITH_STOPWORDS= 1,
 
-/*
-  Parse in boolean mode.  This mode is used to parse a boolean query string.
-
-  The parser should provide a valid MYSQL_FTPARSER_BOOLEAN_INFO
-  structure in the 'boolean_info' argument to mysql_add_word().
-  Usually that means that the parser should recognize boolean operators
-  in the parsing stream and set appropriate fields in
-  MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly.  As for
-  MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored.
-  Instead, use FT_TOKEN_STOPWORD for the token type of such a word.
-*/
-  MYSQL_FTPARSER_FULL_BOOLEAN_INFO= 2
-};
+/* handlertons of different MySQL releases are incompatible */
+#define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
 
 /*
-  Token types for boolean mode searching (used for the type member of
-  MYSQL_FTPARSER_BOOLEAN_INFO struct)
-
-  FT_TOKEN_EOF: End of data.
-  FT_TOKEN_WORD: Regular word.
-  FT_TOKEN_LEFT_PAREN: Left parenthesis (start of group/sub-expression).
-  FT_TOKEN_RIGHT_PAREN: Right parenthesis (end of group/sub-expression).
-  FT_TOKEN_STOPWORD: Stopword.
+  Here we define only the descriptor structure, that is referred from
+  st_mysql_plugin.
 */
 
-enum enum_ft_token_type
+struct st_mysql_daemon
 {
-  FT_TOKEN_EOF= 0,
-  FT_TOKEN_WORD= 1,
-  FT_TOKEN_LEFT_PAREN= 2,
-  FT_TOKEN_RIGHT_PAREN= 3,
-  FT_TOKEN_STOPWORD= 4
+  int interface_version;
 };
 
-/*
-  This structure is used in boolean search mode only. It conveys
-  boolean-mode metadata to the MySQL search engine for every word in
-  the search query. A valid instance of this structure must be filled
-  in by the plugin parser and passed as an argument in the call to
-  mysql_add_word (the callback function in the MYSQL_FTPARSER_PARAM
-  structure) when a query is parsed in boolean mode.
-
-  type: The token type.  Should be one of the enum_ft_token_type values.
-
-  yesno: Whether the word must be present for a match to occur:
-    >0 Must be present
-    <0 Must not be present
-    0  Neither; the word is optional but its presence increases the relevance
-  With the default settings of the ft_boolean_syntax system variable,
-  >0 corresponds to the '+' operator, <0 corrresponds to the '-' operator,
-  and 0 means neither operator was used.
-
-  weight_adjust: A weighting factor that determines how much a match
-  for the word counts.  Positive values increase, negative - decrease the
-  relative word's importance in the query.
-
-  wasign: The sign of the word's weight in the query. If it's non-negative
-  the match for the word will increase document relevance, if it's
-  negative - decrease (the word becomes a "noise word", the less of it the
-  better).
 
-  trunc: Corresponds to the '*' operator in the default setting of the
-  ft_boolean_syntax system variable.
+/*************************************************************************
+  API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN)
 */
 
-typedef struct st_mysql_ftparser_boolean_info
-{
-  enum enum_ft_token_type type;
-  int yesno;
-  int weight_adjust;
-  char wasign;
-  char trunc;
-  /* These are parser state and must be removed. */
-  char prev;
-  char *quot;
-} MYSQL_FTPARSER_BOOLEAN_INFO;
-
-/*
-  The following flag means that buffer with a string (document, word)
-  may be overwritten by the caller before the end of the parsing (that is
-  before st_mysql_ftparser::deinit() call). If one needs the string
-  to survive between two successive calls of the parsing function, she
-  needs to save a copy of it. The flag may be set by MySQL before calling
-  st_mysql_ftparser::parse(), or it may be set by a plugin before calling
-  st_mysql_ftparser_param::mysql_parse() or
-  st_mysql_ftparser_param::mysql_add_word().
-*/
-#define MYSQL_FTFLAGS_NEED_COPY 1
+/* handlertons of different MySQL releases are incompatible */
+#define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
 
 /*
-  An argument of the full-text parser plugin. This structure is
-  filled in by MySQL server and passed to the parsing function of the
-  plugin as an in/out parameter.
-
-  mysql_parse: A pointer to the built-in parser implementation of the
-  server. It's set by the server and can be used by the parser plugin
-  to invoke the MySQL default parser.  If plugin's role is to extract
-  textual data from .doc, .pdf or .xml content, it might extract
-  plaintext from the content, and then pass the text to the default
-  MySQL parser to be parsed.
-
-  mysql_add_word: A server callback to add a new word.  When parsing
-  a document, the server sets this to point at a function that adds
-  the word to MySQL full-text index.  When parsing a search query,
-  this function will add the new word to the list of words to search
-  for.  The boolean_info argument can be NULL for all cases except
-  when mode is MYSQL_FTPARSER_FULL_BOOLEAN_INFO.
-
-  ftparser_state: A generic pointer. The plugin can set it to point
-  to information to be used internally for its own purposes.
-
-  mysql_ftparam: This is set by the server.  It is used by MySQL functions
-  called via mysql_parse() and mysql_add_word() callback.  The plugin
-  should not modify it.
-
-  cs: Information about the character set of the document or query string.
-
-  doc: A pointer to the document or query string to be parsed.
-
-  length: Length of the document or query string, in bytes.
-
-  flags: See MYSQL_FTFLAGS_* constants above.
-
-  mode: The parsing mode.  With boolean operators, with stopwords, or
-  nothing.  See  enum_ftparser_mode above.
-*/
-
-typedef struct st_mysql_ftparser_param
-{
-  int (*mysql_parse)(struct st_mysql_ftparser_param *,
-                     char *doc, int doc_len);
-  int (*mysql_add_word)(struct st_mysql_ftparser_param *,
-                        char *word, int word_len,
-                        MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
-  void *ftparser_state;
-  void *mysql_ftparam;
-  struct charset_info_st *cs;
-  char *doc;
-  int length;
-  int flags;
-  enum enum_ftparser_mode mode;
-} MYSQL_FTPARSER_PARAM;
-
-/*
-  Full-text parser descriptor.
-
-  interface_version is, e.g., MYSQL_FTPARSER_INTERFACE_VERSION.
-  The parsing, initialization, and deinitialization functions are
-  invoked per SQL statement for which the parser is used.
+  Here we define only the descriptor structure, that is referred from
+  st_mysql_plugin.
 */
 
-struct st_mysql_ftparser
+struct st_mysql_information_schema
 {
   int interface_version;
-  int (*parse)(MYSQL_FTPARSER_PARAM *param);
-  int (*init)(MYSQL_FTPARSER_PARAM *param);
-  int (*deinit)(MYSQL_FTPARSER_PARAM *param);
 };
 
-/*************************************************************************
-  API for Storage Engine plugin. (MYSQL_DAEMON_PLUGIN)
-*/
-
-/* handlertons of different MySQL releases are incompatible */
-#define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
-
-/*************************************************************************
-  API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN)
-*/
 
-/* handlertons of different MySQL releases are incompatible */
-#define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
 
 /*************************************************************************
   API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN)
@@ -620,28 +464,8 @@ struct st_mysql_storage_engine
 
 struct handlerton;
 
-/*
-  Here we define only the descriptor structure, that is referred from
-  st_mysql_plugin.
-*/
-
-struct st_mysql_daemon
-{
-  int interface_version;
-};
-
-/*
-  Here we define only the descriptor structure, that is referred from
-  st_mysql_plugin.
-*/
-
-struct st_mysql_information_schema
-{
-  int interface_version;
-};
-
 
-/*
+/*************************************************************************
   st_mysql_value struct for reading values from mysqld.
   Used by server variables framework to parse user-provided values.
   Will be used for arguments when implementing UDFs.
diff -Nrup a/libmysqld/Makefile.am b/libmysqld/Makefile.am
--- a/libmysqld/Makefile.am	2007-11-01 11:37:47 -07:00
+++ b/libmysqld/Makefile.am	2007-11-29 14:40:16 -08:00
@@ -76,7 +76,7 @@ sqlsources = derror.cc field.cc field_co
 	rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
 	sql_tablespace.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
-	sql_servers.cc
+	sql_servers.cc sql_audit.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources)
 nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
diff -Nrup a/plugin/audit_null/AUTHORS b/plugin/audit_null/AUTHORS
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/AUTHORS	2007-11-29 14:40:18 -08:00
@@ -0,0 +1 @@
+AUTHORS file example for a plugin
diff -Nrup a/plugin/audit_null/ChangeLog b/plugin/audit_null/ChangeLog
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/ChangeLog	2007-11-29 14:40:18 -08:00
@@ -0,0 +1 @@
+ChangeLog file example for a plugin
diff -Nrup a/plugin/audit_null/Makefile.am b/plugin/audit_null/Makefile.am
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/Makefile.am	2007-11-29 14:40:18 -08:00
@@ -0,0 +1,27 @@
+# Copyright (C) 2007 MySQL AB
+#
+# 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# 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
+
+#Makefile.am example for a plugin
+
+pkglibdir=$(libdir)/mysql
+INCLUDES= -I$(top_builddir)/include -I$(top_srcdir)/include
+#noinst_LTLIBRARIES= adt_null.la
+pkglib_LTLIBRARIES= adt_null.la
+adt_null_la_SOURCES= audit_null.c
+adt_null_la_LDFLAGS= -module -rpath $(pkglibdir)
+adt_null_la_CFLAGS= -DMYSQL_DYNAMIC_PLUGIN
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff -Nrup a/plugin/audit_null/NEWS b/plugin/audit_null/NEWS
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/NEWS	2007-11-29 14:40:19 -08:00
@@ -0,0 +1 @@
+NEWS file example for a plugin
diff -Nrup a/plugin/audit_null/README b/plugin/audit_null/README
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/README	2007-11-29 14:40:19 -08:00
@@ -0,0 +1 @@
+README file example for a plugin
diff -Nrup a/plugin/audit_null/audit_null.c b/plugin/audit_null/audit_null.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/audit_null.c	2007-11-29 14:40:19 -08:00
@@ -0,0 +1,142 @@
+/* Copyright (C) 2006-2007 MySQL AB
+
+   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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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 */
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <my_atomic.h>
+#include <mysql/audit.h>
+
+#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__)  || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
+#define __attribute__(A)
+#endif
+
+static volatile uint32 number_of_calls; /* for SHOW STATUS, see below */
+static my_atomic_rwlock_t rwl;
+
+
+/*
+  Initialize the plugin at server start or plugin installation.
+
+  SYNOPSIS
+    null_audit_plugin_init()
+
+  DESCRIPTION
+    Does nothing.
+
+  RETURN VALUE
+    0                    success
+    1                    failure (cannot happen)
+*/
+
+static int null_audit_plugin_init(void *arg __attribute__((unused)))
+{
+  my_atomic_rwlock_init(&rwl);
+  number_of_calls= 0;
+  return(0);
+}
+
+
+/*
+  Terminate the plugin at server shutdown or plugin deinstallation.
+
+  SYNOPSIS
+    null_audit_plugin_deinit()
+    Does nothing.
+
+  RETURN VALUE
+    0                    success
+    1                    failure (cannot happen)
+
+*/
+
+static int null_audit_plugin_deinit(void *arg __attribute__((unused)))
+{
+  my_atomic_rwlock_destroy(&rwl);
+  printf("audit_null was invoked %lu times\n",
+         (ulong) number_of_calls);
+  return(0);
+}
+
+
+/*
+  Foo
+
+  SYNOPSIS
+    null_notify()
+      thd                connection context
+
+  DESCRIPTION
+*/
+
+static void null_notify(MYSQL_THD thd __attribute__((unused)),
+                        const struct mysql_event *event
+                        __attribute__((unused)))
+{
+  my_atomic_rwlock_wrlock(&rwl);
+  my_atomic_add32(&number_of_calls, 1);
+  my_atomic_rwlock_wrunlock(&rwl);
+}
+
+
+static unsigned long long null_audit_mask[]=
+{
+  (unsigned long long) -1
+};
+
+
+/*
+  Plugin type-specific descriptor
+*/
+
+static struct st_mysql_audit null_audit_descriptor=
+{
+  MYSQL_AUDIT_INTERFACE_VERSION,    /* interface version      */
+  null_audit_mask,                  /* class mask             */
+  NULL,                             /* release_thd function   */
+  null_notify                       /* notify function        */
+};
+
+/*
+  Plugin status variables for SHOW STATUS
+*/
+
+static struct st_mysql_show_var simple_status[]=
+{
+  {"null_audit_called", (char *)&number_of_calls, SHOW_INT},
+  {0,0,0}
+};
+
+
+/*
+  Plugin library descriptor
+*/
+
+mysql_declare_plugin(null_audit)
+{
+  MYSQL_AUDIT_PLUGIN,         /* type                            */
+  &null_audit_descriptor,     /* descriptor                      */
+  "NULL_AUDIT",               /* name                            */
+  "MySQL AB",                 /* author                          */
+  "Simple NULL Audit",        /* description                     */
+  PLUGIN_LICENSE_GPL,
+  null_audit_plugin_init,     /* init function (when loaded)     */
+  null_audit_plugin_deinit,   /* deinit function (when unloaded) */
+  0x0001,                     /* version                         */
+  simple_status,              /* status variables                */
+  NULL,                       /* system variables                */
+  NULL
+}
+mysql_declare_plugin_end;
+
diff -Nrup a/plugin/audit_null/configure.in b/plugin/audit_null/configure.in
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/configure.in	2007-11-29 14:40:19 -08:00
@@ -0,0 +1,9 @@
+# configure.in example for a plugin
+
+AC_INIT(audit_null, 0.1)
+AM_INIT_AUTOMAKE
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
+
diff -Nrup a/plugin/audit_null/plug.in b/plugin/audit_null/plug.in
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/plugin/audit_null/plug.in	2007-11-29 14:40:19 -08:00
@@ -0,0 +1,3 @@
+MYSQL_PLUGIN(audit_null,         [NULL Audit Plug-in],
+        [Simple black-hole Audit example plug-in])
+MYSQL_PLUGIN_DYNAMIC(audit_null, [adt_null.la])
diff -Nrup a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c
--- a/plugin/fulltext/plugin_example.c	2007-04-26 12:25:58 -07:00
+++ b/plugin/fulltext/plugin_example.c	2007-11-29 14:40:16 -08:00
@@ -15,7 +15,7 @@
 
 #include <stdlib.h>
 #include <ctype.h>
-#include <mysql/plugin.h>
+#include <mysql/ftparser.h>
 
 #if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__)  || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
 #define __attribute__(A)
diff -Nrup a/sql/Makefile.am b/sql/Makefile.am
--- a/sql/Makefile.am	2007-11-01 11:37:48 -07:00
+++ b/sql/Makefile.am	2007-11-29 14:40:16 -08:00
@@ -84,7 +84,7 @@ noinst_HEADERS =	item.h item_func.h item
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.h \
 			probes.h \
-			contributors.h sql_servers.h
+			contributors.h sql_servers.h sql_audit.h
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -127,7 +127,7 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
                         event_queue.cc event_db_repository.cc events.cc \
 			sql_plugin.cc sql_binlog.cc \
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
-			sql_servers.cc
+			sql_servers.cc sql_audit.cc
 
 if HAVE_DTRACE
   mysqld_SOURCES += probes.d
diff -Nrup a/sql/event_queue.cc b/sql/event_queue.cc
--- a/sql/event_queue.cc	2007-08-25 01:43:10 -07:00
+++ b/sql/event_queue.cc	2007-11-29 14:40:16 -08:00
@@ -16,6 +16,7 @@
 #include "mysql_priv.h"
 #include "event_queue.h"
 #include "event_data_objects.h"
+#include "sql_audit.h"
 
 /**
   @addtogroup Event_Scheduler
@@ -547,6 +548,9 @@ Event_queue::get_top_for_execution_if_ti
       /* There are no events in the queue */
       next_activation_at= 0;
 
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+
       /* Wait on condition until signaled. Release LOCK_queue while waiting. */
       cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
 
@@ -566,6 +570,10 @@ Event_queue::get_top_for_execution_if_ti
       */
       struct timespec top_time;
       set_timespec(top_time, next_activation_at - thd->query_start());
+
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+
       cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
 
       continue;
diff -Nrup a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
--- a/sql/ha_ndbcluster_binlog.cc	2007-11-13 03:52:17 -08:00
+++ b/sql/ha_ndbcluster_binlog.cc	2007-11-29 14:40:16 -08:00
@@ -23,6 +23,7 @@
 #include "rpl_injector.h"
 #include "rpl_filter.h"
 #include "slave.h"
+#include "sql_audit.h"
 #include "ha_ndbcluster_binlog.h"
 #include "NdbDictionary.hpp"
 #include "ndb_cluster_connection.hpp"
@@ -491,8 +492,12 @@ static void ndbcluster_binlog_wait(THD *
     ulonglong wait_epoch= get_latest_trans_gci();
     int count= 30;
     if (thd)
+    {
       THD_SET_PROC_INFO(thd,
         "Waiting for ndbcluster binlog update to reach current position");
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+    }
     pthread_mutex_lock(&injector_mutex);
     while (!thd->killed && count && ndb_binlog_running &&
            (ndb_latest_handled_binlog_epoch == 0 ||
@@ -1610,6 +1615,9 @@ end:
         if (ndb_extra_logging)
           ndb_report_waiting(type_str, max_timeout,
                              "distributing", ndb_schema_object->key);
+
+        /* Release any held audit resources */
+        mysql_audit_release(thd);
       }
     }
     if (have_lock_open)
@@ -3402,6 +3410,9 @@ ndbcluster_handle_alter_table(THD *thd, 
       if (ndb_extra_logging)
         ndb_report_waiting(type_str, max_timeout,
                            type_str, share->key);
+
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
     }
   }
   (void) pthread_mutex_unlock(&share->mutex);
@@ -3472,6 +3483,9 @@ ndbcluster_handle_drop_table(THD *thd, N
       if (ndb_extra_logging)
         ndb_report_waiting(type_str, max_timeout,
                            type_str, share->key);
+
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
     }
   }
   (void) pthread_mutex_lock(&LOCK_open);
@@ -4288,6 +4302,10 @@ restart:
       /* ndb not connected yet */
       struct timespec abstime;
       set_timespec(abstime, 1);
+
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+
       pthread_cond_timedwait(&injector_cond, &injector_mutex, &abstime);
       if (ndbcluster_binlog_terminating)
       {
@@ -4320,6 +4338,9 @@ restart:
     {
       DBUG_PRINT("info", ("Waiting for the first event"));
 
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+
       if (ndbcluster_binlog_terminating)
         goto err;
 
@@ -4450,6 +4471,10 @@ restart:
                   (uint)(gci >> 32),
                   (uint)(gci));
       THD_SET_PROC_INFO(thd, buf);
+
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+
       schema_res= s_ndb->pollEvents(10, &schema_gci);
     }
 
diff -Nrup a/sql/log.cc b/sql/log.cc
--- a/sql/log.cc	2007-11-14 02:01:42 -08:00
+++ b/sql/log.cc	2007-11-29 14:40:16 -08:00
@@ -21,6 +21,7 @@
 #include "sql_repl.h"
 #include "rpl_filter.h"
 #include "rpl_rli.h"
+#include "sql_audit.h"
 
 #include <my_dir.h>
 #include <stdarg.h>
@@ -975,6 +976,14 @@ bool LOGGER::general_log_write(THD *thd,
                                                           user_host_buff;
 
   current_time= my_time(0);
+
+  MYSQL_AUDIT_GENERAL(thd, MYSQL_AUDIT_GENERAL_LOG, 0, current_time,
+                      user_host_buff, user_host_len,
+                      command_name[(uint) command].str,
+                      command_name[(uint) command].length,
+                      query, query_length,
+                      thd->variables.character_set_client,0);
+                        
   while (*current_handler)
     error+= (*current_handler++)->
       log_general(thd, current_time, user_host_buff,
@@ -4376,7 +4385,8 @@ int vprint_msg_to_log(enum loglevel leve
   DBUG_RETURN(0);
 }
 #else /*!EMBEDDED_LIBRARY*/
-static void print_buffer_to_file(enum loglevel level, const char *buffer)
+static void print_buffer_to_file(enum loglevel level, int error_code,
+                                 const char *buffer, size_t buffer_length)
 {
   time_t skr;
   struct tm tm_tmp;
@@ -4387,6 +4397,33 @@ static void print_buffer_to_file(enum lo
   VOID(pthread_mutex_lock(&LOCK_error_log));
 
   skr= my_time(0);
+
+  {
+    char user_host_buff[MAX_USER_HOST_SIZE];
+    THD *thd;
+	ulong id= 0;
+    uint user_host_len= 0;
+
+	if ((thd= current_thd))
+	{
+      Security_context *sctx= thd->security_ctx;
+	  id= thd->thread_id;
+	  user_host_len= strxnmov(user_host_buff, MAX_USER_HOST_SIZE,
+                        	  sctx->priv_user ? sctx->priv_user : "", "[",
+                        	  sctx->user ? sctx->user : "", "] @ ",
+                        	  sctx->host ? sctx->host : "", " [",
+                        	  sctx->ip ? sctx->ip : "", "]", NullS) -
+                                                        	  user_host_buff;
+	}
+    MYSQL_AUDIT_GENERAL(thd, MYSQL_AUDIT_GENERAL_CONSOLE, error_code, skr,
+                        user_host_buff, user_host_len,
+                        (level == ERROR_LEVEL ? "ERROR" : 
+                         level == WARNING_LEVEL ? "Warning" : "Note"),
+                        (level == ERROR_LEVEL ? 5 :
+                         level == WARNING_LEVEL ? 7 : 4),
+                        buffer, buffer_length,0,0);
+  }
+
   localtime_r(&skr, &tm_tmp);
   start=&tm_tmp;
 
@@ -4412,10 +4449,12 @@ int vprint_msg_to_log(enum loglevel leve
 {
   char   buff[1024];
   size_t length;
+  int error_code= errno;
   DBUG_ENTER("vprint_msg_to_log");
 
   length= my_vsnprintf(buff, sizeof(buff), format, args);
-  print_buffer_to_file(level, buff);
+
+  print_buffer_to_file(level, error_code, buff, length);
 
 #ifdef __NT__
   print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff));
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc	2007-11-22 11:45:19 -08:00
+++ b/sql/mysqld.cc	2007-11-29 14:40:16 -08:00
@@ -26,6 +26,7 @@
 #include "mysqld_suffix.h"
 #include "mysys_err.h"
 #include "events.h"
+#include "sql_audit.h"
 
 #include "../storage/myisam/ha_myisam.h"
 
@@ -1266,6 +1267,7 @@ void clean_up(bool print_message)
 #endif
 
 #if !defined(EMBEDDED_LIBRARY)
+  mysql_audit_finalize();
   if (!opt_bootstrap)
     (void) my_delete(pidfile_name,MYF(0));	// This may not always exist
 #endif
@@ -3252,6 +3254,11 @@ static void end_ssl()
 static int init_server_components()
 {
   DBUG_ENTER("init_server_components");
+
+#ifndef EMBEDDED_LIBRARY
+  mysql_audit_initialize();
+#endif
+
   /*
     We need to call each of these following functions to ensure that
     all things are initialized so that unireg_abort() doesn't fail
diff -Nrup a/sql/protocol.cc b/sql/protocol.cc
--- a/sql/protocol.cc	2007-11-01 04:32:31 -07:00
+++ b/sql/protocol.cc	2007-11-29 14:40:17 -08:00
@@ -24,6 +24,7 @@
 
 #include "mysql_priv.h"
 #include "sp_rcontext.h"
+#include "sql_audit.h"
 #include <stdarg.h>
 
 static const unsigned int PACKET_BUFFER_EXTRA_ALLOC= 1024;
@@ -132,6 +133,12 @@ void net_send_error(THD *thd, uint sql_e
 
   DBUG_ASSERT(!thd->spcont);
 
+  MYSQL_AUDIT_GENERAL(thd,MYSQL_AUDIT_GENERAL_ERROR,sql_errno,my_time(0),
+					  0,0,err,err?strlen(err):0,
+					  thd->query,thd->query_length,
+					  thd->variables.character_set_client,
+					  thd->row_count);
+
   if (net && net->no_send_error)
   {
     thd->clear_error();
@@ -210,6 +217,12 @@ send_ok(THD *thd, ha_rows affected_rows,
   NET *net= &thd->net;
   uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
   DBUG_ENTER("send_ok");
+
+  MYSQL_AUDIT_GENERAL(thd,MYSQL_AUDIT_GENERAL_RESULT,0,my_time(0),
+					  0,0,message,message?strlen(message):0,
+					  thd->query,thd->query_length,
+					  thd->variables.character_set_client,
+					  affected_rows);  
 
   if (net->no_send_ok || !net->vio)	// hack for re-parsing queries
   {
diff -Nrup a/sql/scheduler.cc b/sql/scheduler.cc
--- a/sql/scheduler.cc	2007-11-02 12:39:00 -07:00
+++ b/sql/scheduler.cc	2007-11-29 14:40:17 -08:00
@@ -22,6 +22,7 @@
 #endif
 
 #include <mysql_priv.h>
+#include "sql_audit.h"
 
 
 /*
@@ -396,6 +397,8 @@ static void libevent_connection_close(TH
 
   thd->killed= THD::KILL_CONNECTION;          // Avoid error messages
 
+  mysql_audit_release(thd);
+
   if (thd->net.vio->sd >= 0)                   // not already closed
   {
     end_connection(thd);
@@ -539,6 +542,8 @@ static bool libevent_needs_immediate_pro
   */
   if (thd->net.vio == 0 || thd->net.vio->read_pos < thd->net.vio->read_end)
     return TRUE;
+
+  mysql_audit_release(thd);
     
   /*
     Send to be queued for libevent.
diff -Nrup a/sql/slave.cc b/sql/slave.cc
--- a/sql/slave.cc	2007-11-22 11:45:20 -08:00
+++ b/sql/slave.cc	2007-11-29 14:40:17 -08:00
@@ -23,6 +23,7 @@
 #include "sql_repl.h"
 #include "rpl_filter.h"
 #include "repl_failsafe.h"
+#include "sql_audit.h"
 #include <thr_alarm.h>
 #include <my_dir.h>
 #include <sql_common.h>
@@ -1572,6 +1573,9 @@ static int exec_relay_log_event(THD* thd
     DBUG_RETURN(1);
   }
 
+  /* Release any held audit resources */
+  mysql_audit_release(thd);
+
   Log_event * ev = next_event(rli);
 
   DBUG_ASSERT(rli->sql_thd==thd);
@@ -1830,6 +1834,10 @@ static int try_to_reconnect(THD *thd, MY
   {
     if (*retry_count > master_retry_count)
       return 1;                             // Don't retry forever
+
+    /* Release any held audit resources */
+    mysql_audit_release(thd);
+
     safe_sleep(thd, mi->connect_retry, (CHECK_KILLED_FUNC) io_slave_killed,
                (void *) mi);
   }
@@ -1856,6 +1864,10 @@ static int try_to_reconnect(THD *thd, MY
       sql_print_information(buf);
     }
   }
+
+  /* Release any held audit resources */
+  mysql_audit_release(thd);
+
   if (safe_reconnect(thd, mysql, mi, 1) || io_slave_killed(thd, mi))
   {
     if (global_system_variables.log_warnings)
@@ -1951,6 +1963,8 @@ pthread_handler_t handle_slave_io(void *
   }
 
 connected:
+  /* Release any held audit resources */
+  mysql_audit_release(thd);
 
   // TODO: the assignment below should be under mutex (5.0)
   mi->slave_running= MYSQL_SLAVE_RUN_CONNECT;
@@ -2022,6 +2036,10 @@ requesting master dump") ||
          we're in fact receiving nothing.
       */
       THD_SET_PROC_INFO(thd, "Waiting for master to send event");
+
+      /* Release any held audit resources */
+      mysql_audit_release(thd);
+
       event_len= read_event(mysql, mi, &suppress_warnings);
       if (check_io_slave_killed(thd, mi, "Slave I/O thread killed while \
 reading event"))
diff -Nrup a/sql/sql_acl.cc b/sql/sql_acl.cc
--- a/sql/sql_acl.cc	2007-11-13 03:52:18 -08:00
+++ b/sql/sql_acl.cc	2007-11-29 14:40:17 -08:00
@@ -30,6 +30,7 @@
 #include <stdarg.h>
 #include "sp_head.h"
 #include "sp.h"
+#include "sql_audit.h"
 
 time_t mysql_db_table_last_check= 0L;
 
@@ -672,6 +673,8 @@ my_bool acl_reload(THD *thd)
   my_bool return_val= 1;
   DBUG_ENTER("acl_reload");
 
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_RELOAD,0,"ACLS",0,0,0,0);
+
   if (thd->locked_tables)
   {					// Can't have locked tables here
     thd->lock=thd->locked_tables;
@@ -1473,14 +1476,27 @@ void rebuild_check_host(void)
 
 bool acl_check_host(const char *host, const char *ip)
 {
+  THD *thd= NULL;
+  LEX_STRING host_str= {(char*) host, host ? strlen(host) : 0 };
+  LEX_STRING ip_str= {(char*) ip, ip ? strlen(ip) : 0 };
+
+  MYSQL_AUDIT_SECURITY((thd=current_thd),MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "HOST",0,&host_str,&ip_str,0);
+
   if (allow_all_hosts)
+  {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                         "HOST",0,&host_str,&ip_str,0);
     return 0;
+  }
   VOID(pthread_mutex_lock(&acl_cache->lock));
 
-  if (host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host)) ||
-      ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))
+  if (host && hash_search(&acl_check_hosts,(uchar*) host_str.str, host_str.length) ||
+      ip && hash_search(&acl_check_hosts,(uchar*) ip_str.str, ip_str.length))
   {
     VOID(pthread_mutex_unlock(&acl_cache->lock));
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                         "HOST",0,&host_str,&ip_str,0);
     return 0;					// Found host
   }
   for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
@@ -1489,10 +1505,14 @@ bool acl_check_host(const char *host, co
     if (compare_hostname(acl, host, ip))
     {
       VOID(pthread_mutex_unlock(&acl_cache->lock));
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                           "HOST",0,&host_str,&ip_str,0);
       return 0;					// Host ok
     }
   }
   VOID(pthread_mutex_unlock(&acl_cache->lock));
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                       "HOST",0,&host_str,&ip_str,0);
   return 1;					// Host is not allowed
 }
 
@@ -1518,6 +1538,9 @@ bool acl_check_host(const char *host, co
 bool check_change_password(THD *thd, const char *host, const char *user,
                            char *new_password, uint new_password_len)
 {
+#ifndef EMBEDDED_LIBRARY
+  LEX_STRING user_str= { (char*) user, strlen(user) };
+#endif
   if (!initialized)
   {
     my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
@@ -1531,8 +1554,12 @@ bool check_change_password(THD *thd, con
     if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0))
       return(1);
   }
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "PASSWORD",0,&user_str,0,0);
   if (!thd->slave_thread && !thd->security_ctx->user[0])
   {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                         "PASSWORD",0,&user_str,0,0);
     my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
                MYF(0));
     return(1);
@@ -1541,9 +1568,13 @@ bool check_change_password(THD *thd, con
   if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
       len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
   {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                         "PASSWORD",0,&user_str,0,0);
     my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
     return -1;
   }
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                       "PASSWORD",0,&user_str,0,0);
   return(0);
 }
 
@@ -1662,14 +1693,23 @@ end:
 bool is_acl_user(const char *host, const char *user)
 {
   bool res;
+#ifndef EMBEDDED_LIBRARY
+  THD *thd= NULL;
+  LEX_STRING host_str= { (char*) host, host ? strlen(host) : 0};
+  LEX_STRING user_str= { (char*) user, strlen(user) };
+#endif
 
   /* --skip-grants */
   if (!initialized)
     return TRUE;
 
+  MYSQL_AUDIT_SECURITY((thd=current_thd),MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "USER",0,&user_str,&host_str,0);
   VOID(pthread_mutex_lock(&acl_cache->lock));
   res= find_acl_user(host, user, TRUE) != NULL;
   VOID(pthread_mutex_unlock(&acl_cache->lock));
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,res,
+                       "USER",0,&user_str,&host_str,0);
   return res;
 }
 
@@ -2926,7 +2966,7 @@ bool mysql_table_grant(THD *thd, TABLE_L
   LEX_USER *Str, *tmp_Str;
   TABLE_LIST tables[3];
   bool create_new_users=0;
-  char *db_name, *table_name;
+  LEX_STRING db_name, table_name;
   DBUG_ENTER("mysql_table_grant");
 
   if (!initialized)
@@ -2942,6 +2982,18 @@ bool mysql_table_grant(THD *thd, TABLE_L
     DBUG_RETURN(TRUE);
   }
 
+  if (revoke_grant || !columns.elements)
+  {
+    if (table_list->view_db.length)
+      db_name= table_list->view_db;
+    else
+      db_name.length= strlen(db_name.str= table_list->db);
+    if (table_list->view_name.length)
+      table_name= table_list->view_name;
+    else
+      table_name.length= strlen(table_name.str= table_list->table_name);
+  }
+  
   if (!revoke_grant)
   {
     if (columns.elements)
@@ -2952,15 +3004,28 @@ bool mysql_table_grant(THD *thd, TABLE_L
       if (open_and_lock_tables(thd, table_list))
         DBUG_RETURN(TRUE);
 
+      if (table_list->view_db.length)
+        db_name= table_list->view_db;
+      else
+        db_name.length= strlen(db_name.str= table_list->db);
+      if (table_list->view_name.length)
+        table_name= table_list->view_name;
+      else
+        table_name.length= strlen(table_name.str= table_list->table_name);
+
       while ((column = column_iter++))
       {
         uint unused_field_idx= NO_CACHED_FIELD_INDEX;
         TABLE_LIST *dummy;
-        Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
-                                         column->column.length(),
-                                         column->column.ptr(), NULL, NULL,
+        LEX_STRING column_name= 
+          {(char*)column->column.ptr(),column->column.length()};
+        Field *f=find_field_in_table_ref(thd, table_list, column_name.str,
+                                         column_name.length,
+                                         column_name.str, NULL, NULL,
                                          NULL, TRUE, FALSE,
                                          &unused_field_idx, FALSE, &dummy);
+    	MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                        	 "COLUMN",&db_name,&table_name,&column_name,rights);
         if (f == (Field*)0)
         {
           my_error(ER_BAD_FIELD_ERROR, MYF(0),
@@ -2975,6 +3040,9 @@ bool mysql_table_grant(THD *thd, TABLE_L
     }
     else
     {
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                           "TABLE",&db_name,&table_name,0,rights);
+
       if (!(rights & CREATE_ACL))
       {
         char buf[FN_REFLEN];
@@ -2984,6 +3052,8 @@ bool mysql_table_grant(THD *thd, TABLE_L
                                     MY_RETURN_REAL_PATH | MY_APPEND_EXT);
         if (access(buf,F_OK))
         {
+          MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,1,
+                               "TABLE",&db_name,&table_name,0,rights);
           my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
           DBUG_RETURN(TRUE);
         }
@@ -2991,6 +3061,8 @@ bool mysql_table_grant(THD *thd, TABLE_L
       if (table_list->grant.want_privilege)
       {
         char command[128];
+        MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                             "TABLE",&db_name,&table_name,0,rights);
         get_privilege_desc(command, sizeof(command),
                            table_list->grant.want_privilege);
         my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
@@ -3000,6 +3072,26 @@ bool mysql_table_grant(THD *thd, TABLE_L
       }
     }
   }
+#ifndef EMBEDDED_LIBRARY
+  else
+  {
+    if (columns.elements)
+    {
+      class LEX_COLUMN *column;
+      List_iterator <LEX_COLUMN> column_iter(columns);
+      while ((column = column_iter++))
+      {
+        LEX_STRING column_name=
+          {(char*)column->column.ptr(),column->column.length()};
+    	MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                        	 "COLUMN",&db_name,&table_name,&column_name,rights);
+      }
+	}
+	else
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                           "TABLE",&db_name,&table_name,0,rights);
+  }
+#endif
 
   /* open the mysql.tables_priv and mysql.columns_priv tables */
 
@@ -3067,7 +3159,7 @@ bool mysql_table_grant(THD *thd, TABLE_L
     }  
     /* Create user if needed */
     error=replace_user_table(thd, tables[0].table, *Str,
-			     0, revoke_grant, create_new_users,
+                             0, revoke_grant, create_new_users,
                              test(thd->variables.sql_mode &
                                   MODE_NO_AUTO_CREATE_USER));
     if (error)
@@ -3076,33 +3168,26 @@ bool mysql_table_grant(THD *thd, TABLE_L
       continue;					// Add next user
     }
 
-    db_name= (table_list->view_db.length ?
-	      table_list->view_db.str :
-	      table_list->db);
-    table_name= (table_list->view_name.length ?
-		table_list->view_name.str :
-		table_list->table_name);
-
     /* Find/create cached table grant */
-    grant_table= table_hash_search(Str->host.str, NullS, db_name,
-				   Str->user.str, table_name, 1);
+    grant_table= table_hash_search(Str->host.str, NullS, db_name.str,
+                                   Str->user.str, table_name.str, 1);
     if (!grant_table)
     {
       if (revoke_grant)
       {
-	my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
+        my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
                  Str->user.str, Str->host.str, table_list->table_name);
-	result= TRUE;
-	continue;
+        result= TRUE;
+        continue;
       }
-      grant_table = new GRANT_TABLE (Str->host.str, db_name,
-				     Str->user.str, table_name,
-				     rights,
-				     column_priv);
+      grant_table = new GRANT_TABLE (Str->host.str, db_name.str,
+                                     Str->user.str, table_name.str,
+                                     rights,
+                                     column_priv);
       if (!grant_table)				// end of memory
       {
-	result= TRUE;				/* purecov: deadcode */
-	continue;				/* purecov: deadcode */
+        result= TRUE;				/* purecov: deadcode */
+        continue;				/* purecov: deadcode */
       }
       my_hash_insert(&column_priv_hash,(uchar*) grant_table);
     }
@@ -3117,7 +3202,7 @@ bool mysql_table_grant(THD *thd, TABLE_L
       /* Fix old grants */
       while ((column = column_iter++))
       {
-	grant_column = column_hash_search(grant_table,
+        grant_column = column_hash_search(grant_table,
 					  column->column.ptr(),
 					  column->column.length());
 	if (grant_column)
@@ -3142,7 +3227,7 @@ bool mysql_table_grant(THD *thd, TABLE_L
     /* update table and columns */
 
     if (replace_table_table(thd, grant_table, tables[1].table, *Str,
-			    db_name, table_name,
+			    db_name.str, table_name.str,
 			    rights, column_priv, revoke_grant))
     {
       /* Should only happen if table is crashed */
@@ -3152,7 +3237,7 @@ bool mysql_table_grant(THD *thd, TABLE_L
     {
       if ((replace_column_table(grant_table, tables[2].table, *Str,
 				columns,
-				db_name, table_name,
+				db_name.str, table_name.str,
 				rights, revoke_grant)))
       {
 	result= TRUE;
@@ -3202,7 +3287,7 @@ bool mysql_routine_grant(THD *thd, TABLE
   LEX_USER *Str, *tmp_Str;
   TABLE_LIST tables[2];
   bool create_new_users=0, result=0;
-  char *db_name, *table_name;
+  LEX_STRING db_name, table_name;
   DBUG_ENTER("mysql_routine_grant");
 
   if (!initialized)
@@ -3220,11 +3305,25 @@ bool mysql_routine_grant(THD *thd, TABLE
     DBUG_RETURN(TRUE);
   }
 
+  db_name.length= strlen(db_name.str= table_list->db);
+  table_name.length= strlen(table_name.str= table_list->table_name);
+
+#ifndef EMBEDDED_LIBRARY
+  LEX_STRING routine_type;
+  routine_type.str= is_proc ? (char*)"PROCEDURE" : (char*)"FUNCTION";
+  routine_type.length= is_proc ? 9 : 8;
+#endif
+
   if (!revoke_grant)
   {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+	                     "ROUTINE",&db_name,&table_name,&routine_type,rights);
     if (sp_exist_routines(thd, table_list, is_proc, no_error)<0)
       DBUG_RETURN(TRUE);
   }
+  else
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                         "ROUTINE",&db_name,&table_name,&routine_type,rights);
 
   /* open the mysql.user and mysql.procs_priv tables */
 
@@ -3294,23 +3393,20 @@ bool mysql_routine_grant(THD *thd, TABLE
       continue;					// Add next user
     }
 
-    db_name= table_list->db;
-    table_name= table_list->table_name;
-
-    grant_name= routine_hash_search(Str->host.str, NullS, db_name,
-                                    Str->user.str, table_name, is_proc, 1);
+    grant_name= routine_hash_search(Str->host.str, NullS, db_name.str,
+                                    Str->user.str, table_name.str, is_proc, 1);
     if (!grant_name)
     {
       if (revoke_grant)
       {
         if (!no_error)
           my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
-		   Str->user.str, Str->host.str, table_name);
+		   Str->user.str, Str->host.str, table_name.str);
 	result= TRUE;
 	continue;
       }
-      grant_name= new GRANT_NAME(Str->host.str, db_name,
-				 Str->user.str, table_name,
+      grant_name= new GRANT_NAME(Str->host.str, db_name.str,
+				 Str->user.str, table_name.str,
 				 rights);
       if (!grant_name)
       {
@@ -3321,7 +3417,7 @@ bool mysql_routine_grant(THD *thd, TABLE
     }
 
     if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
-			   db_name, table_name, is_proc, rights, revoke_grant))
+			   db_name.str, table_name.str, is_proc, rights, revoke_grant))
     {
       result= TRUE;
       continue;
@@ -3367,6 +3463,21 @@ bool mysql_grant(THD *thd, const char *d
     db=tmp_db;
   }
 
+  LEX_STRING db_name= {(char*) db, db ? strlen(db) : 0};
+
+#ifndef EMBEDDED_LIBRARY
+  while ((tmp_Str = str_list++))
+  {
+	if (!revoke_grant)
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                           "SCHEMA",db?&db_name:0,0,&tmp_Str->user,rights);
+	else
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                           "SCHEMA",db?&db_name:0,0,&tmp_Str->user,rights);
+  }
+  str_list.rewind();
+#endif
+
   /* open the mysql.user and mysql.db tables */
   bzero((char*) &tables,sizeof(tables));
   tables[0].alias=tables[0].table_name=(char*) "user";
@@ -3416,22 +3527,30 @@ bool mysql_grant(THD *thd, const char *d
   int result=0;
   while ((tmp_Str = str_list++))
   {
+	if (!revoke_grant)
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                           "SCHEMA",db?&db_name:0,0,&tmp_Str->user,rights);
+	else
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                           "SCHEMA",db?&db_name:0,0,&tmp_Str->user,rights);
+
     if (!(Str= get_current_user(thd, tmp_Str)))
     {
       result= TRUE;
       continue;
     }
     if (replace_user_table(thd, tables[0].table, *Str,
-                           (!db ? rights : 0), revoke_grant, create_new_users,
+                           (!db_name.str ? rights : 0), revoke_grant, 
+                           create_new_users,
                            test(thd->variables.sql_mode &
                                 MODE_NO_AUTO_CREATE_USER)))
       result= -1;
-    else if (db)
+    else if (db_name.str)
     {
       ulong db_rights= rights & DB_ACLS;
       if (db_rights  == rights)
       {
-	if (replace_db_table(tables[1].table, db, *Str, db_rights,
+	if (replace_db_table(tables[1].table, db_name.str, *Str, db_rights,
 			     revoke_grant))
 	  result= -1;
       }
@@ -3785,13 +3904,19 @@ bool check_grant(THD *thd, ulong want_ac
        table= table->next_global)
   {
     GRANT_TABLE *grant_table;
+    LEX_STRING db_str= {table->db, strlen(table->db)};
+    LEX_STRING table_str={table->table_name, strlen(table->table_name)};
+
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                    	 "TABLE",&db_str,&table_str,0,orig_want_access);
+
     sctx = test(table->security_ctx) ?
       table->security_ctx : thd->security_ctx;
 
     want_access= orig_want_access;
     want_access&= ~sctx->master_access;
     if (!want_access)
-      continue;                                 // ok
+      goto ok;                                 // ok
 
     if (!(~table->grant.privilege & want_access) || 
         table->derived || table->schema_table)
@@ -3809,18 +3934,19 @@ bool check_grant(THD *thd, ulong want_ac
         */
         table->grant.want_privilege= 0;
       }
-      continue;
+      goto ok;
     }
     if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
-                                         table->db, sctx->priv_user,
-                                         table->table_name,0)))
+                                         db_str.str, sctx->priv_user,
+                                         table_str.str,0)))
     {
       want_access &= ~table->grant.privilege;
+	  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                    	   "TABLE",&db_str,&table_str,0,orig_want_access);
       goto err;					// No grants
     }
     if (show_table)
-      continue;					// We have some priv on this
-
+      goto ok;					// We have some priv on this
     table->grant.grant_table=grant_table;	// Remember for column test
     table->grant.version=grant_version;
     table->grant.privilege|= grant_table->privs;
@@ -3828,13 +3954,18 @@ bool check_grant(THD *thd, ulong want_ac
 				  & ~table->grant.privilege);
 
     if (!(~table->grant.privilege & want_access))
-      continue;
+      goto ok;
 
     if (want_access & ~(grant_table->cols | table->grant.privilege))
     {
       want_access &= ~(grant_table->cols | table->grant.privilege);
+	  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                    	   "TABLE",&db_str,&table_str,0,orig_want_access);
       goto err;					// impossible
     }
+ok:
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                         "TABLE",&db_str,&table_str,0,orig_want_access);
   }
   rw_unlock(&LOCK_grant);
   DBUG_RETURN(0);
@@ -3880,11 +4011,22 @@ bool check_grant_column(THD *thd, GRANT_
   GRANT_TABLE *grant_table;
   GRANT_COLUMN *grant_column;
   ulong want_access= grant->want_privilege & ~grant->privilege;
+  LEX_STRING db_str= {(char*) db_name, db_name?strlen(db_name):0};
+  LEX_STRING table_str= {(char*) table_name, table_name?strlen(table_name):0};
+  LEX_STRING column= {(char*) name, length};
   DBUG_ENTER("check_grant_column");
   DBUG_PRINT("enter", ("table: %s  want_access: %lu", table_name, want_access));
 
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "COLUMN",db_name?&db_str:0,table_name?&table_str:0,
+                       &column,grant->want_privilege);
   if (!want_access)
+  {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                       "COLUMN",db_name?&db_str:0,table_name?&table_str:0,
+                       &column,grant->want_privilege);
     DBUG_RETURN(0);				// Already checked
+  }
 
   rw_rdlock(&LOCK_grant);
 
@@ -3893,31 +4035,37 @@ bool check_grant_column(THD *thd, GRANT_
   if (grant->version != grant_version)
   {
     grant->grant_table=
-      table_hash_search(sctx->host, sctx->ip, db_name,
+      table_hash_search(sctx->host, sctx->ip, db_str.str,
 			sctx->priv_user,
-			table_name, 0);         /* purecov: inspected */
+			table_str.str, 0);          /* purecov: inspected */
     grant->version= grant_version;		/* purecov: inspected */
   }
   if (!(grant_table= grant->grant_table))
     goto err;					/* purecov: deadcode */
 
-  grant_column=column_hash_search(grant_table, name, length);
+  grant_column=column_hash_search(grant_table, column.str, column.length);
   if (grant_column && !(~grant_column->rights & want_access))
   {
     rw_unlock(&LOCK_grant);
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                         "COLUMN",db_name?&db_str:0,table_name?&table_str:0,
+                         &column,grant->want_privilege);
     DBUG_RETURN(0);
   }
 
 err:
   rw_unlock(&LOCK_grant);
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                       "COLUMN",db_name?&db_str:0,table_name?&table_str:0,
+                       &column,grant->want_privilege);
   char command[128];
   get_privilege_desc(command, sizeof(command), want_access);
   my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
            command,
            sctx->priv_user,
            sctx->host_or_ip,
-           name,
-           table_name);
+           column.str,
+           table_str.str);
   DBUG_RETURN(1);
 }
 
@@ -3960,20 +4108,35 @@ bool check_column_grant_in_table_ref(THD
     grant= &(table_ref->grant);
     db_name= table_ref->view_db.str;
     table_name= table_ref->view_name.str;
+	LEX_STRING column= {(char*) name, length};
+
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                         "COLUMN",&table_ref->view_db,&table_ref->view_name,
+                         &column, grant->want_privilege);
+
     if (table_ref->belong_to_view && 
         (thd->lex->sql_command == SQLCOM_SHOW_FIELDS ||
          thd->lex->sql_command == SQLCOM_SHOW_CREATE))
     {
-      view_privs= get_column_grant(thd, grant, db_name, table_name, name);
+      view_privs= get_column_grant(thd, grant, db_name, table_name, column.str);
       if (view_privs & VIEW_ANY_ACL)
       {
         table_ref->belong_to_view->allowed_show= TRUE;
+        MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                             "COLUMN",&table_ref->view_db,&table_ref->view_name,
+                             &column, grant->want_privilege);
         return FALSE;
       }
       table_ref->belong_to_view->allowed_show= FALSE;
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                           "COLUMN",&table_ref->view_db,&table_ref->view_name,
+                           &column, grant->want_privilege);
       my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
       return TRUE;
     }
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                         "COLUMN",&table_ref->view_db,&table_ref->view_name,
+                         &column, grant->want_privilege);
   }
   else
   {
@@ -3984,12 +4147,8 @@ bool check_column_grant_in_table_ref(THD
     table_name= table->s->table_name.str;
   }
 
-  if (grant->want_privilege)
-    return check_grant_column(thd, grant, db_name, table_name, name,
-                              length, sctx);
-  else
-    return FALSE;
-
+  return check_grant_column(thd, grant, db_name, table_name, name,
+                            length, sctx);
 }
 
 
@@ -4013,9 +4172,8 @@ bool check_grant_all_columns(THD *thd, u
 {
   Security_context *sctx= thd->security_ctx;
   ulong want_access= want_access_arg;
-  const char *table_name= NULL;
-
-  const char* db_name; 
+  LEX_STRING table_name= {NULL,0};
+  LEX_STRING db_name;
   GRANT_INFO *grant;
   /* Initialized only to make gcc happy */
   GRANT_TABLE *grant_table= NULL;
@@ -4024,12 +4182,12 @@ bool check_grant_all_columns(THD *thd, u
 
   for (; !fields->end_of_fields(); fields->next())
   {
-    const char *field_name= fields->name();
+    LEX_STRING field_name= {(char*) fields->name(), strlen(fields->name())};
 
-    if (table_name != fields->table_name())
+    if (table_name.str != (char*) fields->table_name())
     {
-      table_name= fields->table_name();
-      db_name= fields->db_name();
+      table_name.length= strlen(table_name.str= (char*) fields->table_name());
+      db_name.length= strlen(db_name.str= (char*) fields->db_name());
       grant= fields->grant();
       /* get a fresh one for each table */
       want_access= want_access_arg & ~grant->privilege;
@@ -4039,9 +4197,9 @@ bool check_grant_all_columns(THD *thd, u
         if (grant->version != grant_version)
         {
           grant->grant_table=
-            table_hash_search(sctx->host, sctx->ip, db_name,
+            table_hash_search(sctx->host, sctx->ip, db_name.str,
                               sctx->priv_user,
-                              table_name, 0);	/* purecov: inspected */
+                              table_name.str, 0);	/* purecov: inspected */
           grant->version= grant_version;	/* purecov: inspected */
         }
 
@@ -4050,21 +4208,31 @@ bool check_grant_all_columns(THD *thd, u
       }
     }
 
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                         "COLUMN",&db_name,&table_name,&field_name,
+                         want_access_arg);
+
     if (want_access)
     {
       GRANT_COLUMN *grant_column= 
-        column_hash_search(grant_table, field_name,
-                           (uint) strlen(field_name));
+        column_hash_search(grant_table, field_name.str, field_name.length);
       if (!grant_column || (~grant_column->rights & want_access))
+      {
+        MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                             "COLUMN",&db_name,&table_name,&field_name,
+                             want_access_arg);
         goto err;
+      }
     }
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                         "COLUMN",&db_name,&table_name,&field_name,
+                         want_access_arg);
   }
   rw_unlock(&LOCK_grant);
   return 0;
 
 err:
   rw_unlock(&LOCK_grant);
-
   char command[128];
   get_privilege_desc(command, sizeof(command), want_access);
   my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
@@ -4109,8 +4277,12 @@ bool check_grant_db(THD *thd,const char 
   char helping [NAME_LEN+USERNAME_LENGTH+2];
   uint len;
   bool error= TRUE;
+  LEX_STRING db_str= {(char*) db, strlen(db)};
 
-  len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "SCHEMA",&db_str,0,0,0);
+  len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db_str.str) - 
+               helping) + 1;
 
   rw_rdlock(&LOCK_grant);
 
@@ -4119,7 +4291,7 @@ bool check_grant_db(THD *thd,const char 
     GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
 							  idx);
     if (len < grant_table->key_length &&
-	!memcmp(grant_table->hash_key,helping,len) &&
+        !memcmp(grant_table->hash_key,helping,len) &&
         compare_hostname(&grant_table->host, sctx->host, sctx->ip))
     {
       error= FALSE; /* Found match. */
@@ -4128,11 +4300,12 @@ bool check_grant_db(THD *thd,const char 
   }
 
   if (error)
-    error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
-           check_grant_db_routine(thd, db, &func_priv_hash);
+    error= check_grant_db_routine(thd, db_str.str, &proc_priv_hash) &&
+           check_grant_db_routine(thd, db_str.str, &func_priv_hash);
 
   rw_unlock(&LOCK_grant);
-
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,error,
+                       "SCHEMA",&db_str,0,0,0);
   return error;
 }
 
@@ -4154,35 +4327,62 @@ bool check_grant_db(THD *thd,const char 
      1  Error: User did not have the requested privielges
 ****************************************************************************/
 
-bool check_grant_routine(THD *thd, ulong want_access,
+bool check_grant_routine(THD *thd, ulong want_access_arg,
 			 TABLE_LIST *procs, bool is_proc, bool no_errors)
 {
   TABLE_LIST *table;
   Security_context *sctx= thd->security_ctx;
+  ulong want_access= want_access_arg;
   char *user= sctx->priv_user;
   char *host= sctx->priv_host;
   DBUG_ENTER("check_grant_routine");
 
+#ifndef EMBEDDED_LIBRARY
+  LEX_STRING routine_type;
+  routine_type.str= is_proc ? (char*)"PROCEDURE" : (char*)"FUNCTION";
+  routine_type.length= is_proc ? 9 : 8;
+#endif
+
   want_access&= ~sctx->master_access;
   if (!want_access)
+  {
+#ifndef EMBEDDED_LIBRARY
+    for (table= procs; table; table= table->next_global)
+    {
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                           "ROUTINE",0,0,&routine_type,want_access_arg);
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                           "ROUTINE",0,0,&routine_type,want_access_arg);
+    }
+#endif
     DBUG_RETURN(0);                             // ok
+  }
 
   rw_rdlock(&LOCK_grant);
   for (table= procs; table; table= table->next_global)
   {
     GRANT_NAME *grant_proc;
-    if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
-					 table->table_name, is_proc, 0)))
+    LEX_STRING db= {(char*) table->db, strlen(table->db)};
+    LEX_STRING name= {(char*) table->table_name, strlen(table->table_name)};
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                         "ROUTINE",&db,&name,&routine_type,want_access_arg);
+    if ((grant_proc= routine_hash_search(host, sctx->ip, db.str, user,
+                                         name.str, is_proc, 0)))
       table->grant.privilege|= grant_proc->privs;
 
     if (want_access & ~table->grant.privilege)
     {
       want_access &= ~table->grant.privilege;
+      MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,1,
+                           "ROUTINE",&db,&name,&routine_type,want_access_arg);
       goto err;
     }
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,0,
+                         "ROUTINE",&db,&name,&routine_type,want_access_arg);
   }
   rw_unlock(&LOCK_grant);
   DBUG_RETURN(0);
+
 err:
   rw_unlock(&LOCK_grant);
   if (!no_errors)
@@ -4225,13 +4425,26 @@ bool check_routine_level_acl(THD *thd, c
   bool no_routine_acl= 1;
   GRANT_NAME *grant_proc;
   Security_context *sctx= thd->security_ctx;
+  LEX_STRING db_str= {(char*) db, strlen(db)};
+  LEX_STRING name_str= {(char*) name, strlen(name)};
+
+#ifndef EMBEDDED_LIBRARY
+  LEX_STRING routine_type;
+  routine_type.str= is_proc ? (char*)"PROCEDURE" : (char*)"FUNCTION";
+  routine_type.length= is_proc ? 9 : 8;
+#endif
+
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "ROUTINE",&db_str,&name_str,&routine_type,0);
   rw_rdlock(&LOCK_grant);
   if ((grant_proc= routine_hash_search(sctx->priv_host,
-                                       sctx->ip, db,
+                                       sctx->ip, db_str.str,
                                        sctx->priv_user,
-                                       name, is_proc, 0)))
+                                       name_str.str, is_proc, 0)))
     no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
   rw_unlock(&LOCK_grant);
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,no_routine_acl,
+                       "ROUTINE",&db_str,&name_str,&routine_type,0);
   return no_routine_acl;
 }
 
@@ -4289,7 +4502,12 @@ ulong get_column_grant(THD *thd, GRANT_I
   GRANT_TABLE *grant_table;
   GRANT_COLUMN *grant_column;
   ulong priv;
+  LEX_STRING db_str= {(char*) db_name, strlen(db_name)};
+  LEX_STRING table_str= {(char*) table_name, strlen(table_name)};
+  LEX_STRING field_str= {(char*) field_name, strlen(field_name)};
 
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_ENTER,0,
+                       "COLUMN",&db_str,&table_str,&field_str,0);
   rw_rdlock(&LOCK_grant);
   /* reload table if someone has modified any grants */
   if (grant->version != grant_version)
@@ -4297,8 +4515,8 @@ ulong get_column_grant(THD *thd, GRANT_I
     Security_context *sctx= thd->security_ctx;
     grant->grant_table=
       table_hash_search(sctx->host, sctx->ip,
-                        db_name, sctx->priv_user,
-			table_name, 0);	        /* purecov: inspected */
+                        db_str.str, sctx->priv_user,
+                        table_str.str, 0);      /* purecov: inspected */
     grant->version= grant_version;              /* purecov: inspected */
   }
 
@@ -4306,14 +4524,16 @@ ulong get_column_grant(THD *thd, GRANT_I
     priv= grant->privilege;
   else
   {
-    grant_column= column_hash_search(grant_table, field_name,
-                                     (uint) strlen(field_name));
+    grant_column= column_hash_search(grant_table, field_str.str,
+                                     field_str.length);
     if (!grant_column)
       priv= (grant->privilege | grant_table->privs);
     else
       priv= (grant->privilege | grant_table->privs | grant_column->rights);
   }
   rw_unlock(&LOCK_grant);
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CHECK_LEAVE,priv==0,
+                       "COLUMN",&db_str,&table_str,&field_str,0);
   return priv;
 }
 
@@ -5507,6 +5727,11 @@ bool mysql_create_user(THD *thd, List <L
 
   while ((tmp_user_name= user_list++))
   {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                         "USER",0,&tmp_user_name->user,0,0);
+
+    /* why is this called twice? */
+    user_name= get_current_user(thd, tmp_user_name);
     if (!(user_name= get_current_user(thd, tmp_user_name)))
     {
       result= TRUE;
@@ -5582,7 +5807,9 @@ bool mysql_drop_user(THD *thd, List <LEX
 
   while ((tmp_user_name= user_list++))
   {
-    user_name= get_current_user(thd, tmp_user_name);
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                         "USER",0,&tmp_user_name->user,0,0);
+
     if (!(user_name= get_current_user(thd, tmp_user_name)))
     {
       result= TRUE;
@@ -5732,6 +5959,9 @@ bool mysql_revoke_all(THD *thd,  List <L
   List_iterator <LEX_USER> user_list(list);
   while ((tmp_lex_user= user_list++))
   {
+    MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                         "USER",0,&tmp_lex_user->user,0,0);
+
     if (!(lex_user= get_current_user(thd, tmp_lex_user)))
     {
       result= -1;
@@ -5900,8 +6130,19 @@ bool sp_revoke_privileges(THD *thd, cons
   int result;
   TABLE_LIST tables[GRANT_TABLES];
   HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
+  LEX_STRING db_str= {(char*) sp_db, strlen(sp_db)};
+  LEX_STRING name_str= {(char*) sp_name, strlen(sp_name)};
   DBUG_ENTER("sp_revoke_privileges");
 
+#ifndef EMBEDDED_LIBRARY
+  LEX_STRING routine_type;
+  routine_type.str= is_proc ? (char*)"PROCEDURE" : (char*)"FUNCTION";
+  routine_type.length= is_proc ? 9 : 8;
+#endif
+
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_REVOKE,0,
+                       "ROUTINE",&db_str,&name_str,&routine_type,0);
+
   if ((result= open_grant_tables(thd, tables)))
     DBUG_RETURN(result != 1);
 
@@ -5921,8 +6162,8 @@ bool sp_revoke_privileges(THD *thd, cons
     for (counter= 0, revoked= 0 ; counter < hash->records ; )
     {
       GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
-      if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) &&
-	  !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
+      if (!my_strcasecmp(system_charset_info, grant_proc->db, db_str.str) &&
+	  !my_strcasecmp(system_charset_info, grant_proc->tname, name_str.str))
       {
         LEX_USER lex_user;
 	lex_user.user.str= grant_proc->user;
@@ -5979,8 +6220,19 @@ bool sp_grant_privileges(THD *thd, const
   bool result;
   ACL_USER *au;
   char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
+  LEX_STRING db_str= {(char*) sp_db, strlen(sp_db)};
+  LEX_STRING name_str= {(char*) sp_name, strlen(sp_name)};
   DBUG_ENTER("sp_grant_privileges");
 
+#ifndef EMBEDDED_LIBRARY
+  LEX_STRING routine_type;
+  routine_type.str= is_proc ? (char*)"PROCEDURE" : (char*)"FUNCTION";
+  routine_type.length= is_proc ? 9 : 8;
+#endif
+
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_GRANT,0,
+                       "ROUTINE",&db_str,&name_str,&routine_type,0);
+
   if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
     DBUG_RETURN(TRUE);
 
@@ -6006,8 +6258,8 @@ bool sp_grant_privileges(THD *thd, const
   bzero((char*)tables, sizeof(TABLE_LIST));
   user_list.empty();
 
-  tables->db= (char*)sp_db;
-  tables->table_name= tables->alias= (char*)sp_name;
+  tables->db= db_str.str;
+  tables->table_name= tables->alias= name_str.str;
 
   combo->host.length= strlen(combo->host.str);
   combo->user.length= strlen(combo->user.str);
diff -Nrup a/sql/sql_audit.cc b/sql/sql_audit.cc
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/sql_audit.cc	2007-11-29 14:40:18 -08:00
@@ -0,0 +1,502 @@
+/* Copyright (C) 2007 MySQL AB
+
+   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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "mysql_priv.h"
+#include "sql_audit.h"
+
+extern int initialize_audit_plugin(st_plugin_int *plugin);
+extern int finalize_audit_plugin(st_plugin_int *plugin);
+
+#ifndef EMBEDDED_LIBRARY
+
+uint64 mysql_global_audit_mask1= 0;
+
+
+static void event_class_dispatch(THD *thd, const struct mysql_event *event);
+
+typedef void (*audit_handler_t)(THD *thd, uint event_subtype,
+                                int error_code, va_list ap);
+
+/**
+  MYSQL_AUDIT_GENERAL_CLASS handler
+  
+  @param[in] thd
+  @param[in] event_subtype
+  @param[in] error_code
+  @param[in] ap
+  
+*/
+
+static void general_class_handler(THD *thd, uint event_subtype, 
+                                  int error_code, va_list ap)
+{
+  mysql_event_general event;
+  event.event_class= MYSQL_AUDIT_GENERAL_CLASS;
+  event.general_error_code= error_code;
+  event.general_thread_id= thd ? thd->thread_id : 0;
+  event.general_time= va_arg(ap, time_t);
+  event.general_user= va_arg(ap, const char *);
+  event.general_user_length= va_arg(ap, unsigned int);
+  event.general_command= va_arg(ap, const char *);
+  event.general_command_length= va_arg(ap, unsigned int);
+  event.general_query= va_arg(ap, const char *);
+  event.general_query_length= va_arg(ap, unsigned int);
+  event.general_charset= va_arg(ap, struct charset_info_st *);
+  event.general_rows= (unsigned long long) va_arg(ap, ha_rows);
+  event_class_dispatch(thd, &event);
+}
+
+
+/**
+  MYSQL_AUDIT_SECURITY_CLASS handler
+  
+  @param[in] thd
+  @param[in] event_subtype
+  @param[in] error_code
+  @param[in] ap
+  
+*/
+
+static void security_class_handler(THD *thd, uint event_subtype,
+                                   int error_code, va_list ap)
+{
+  mysql_event_security event;
+  LEX_STRING *str;
+  
+  bzero(&event, sizeof(event));
+  event.event_class= MYSQL_AUDIT_SECURITY_CLASS;
+  event.security_error_code= error_code;
+
+  if (thd)
+  {
+	event.security_thread_id= thd->thread_id;
+    Security_context *ctx= thd->security_ctx;
+	event.security_host= ctx->host;
+	event.security_host_length=
+      event.security_host ? strlen(event.security_host) : 0;
+	event.security_user= ctx->user;
+	event.security_user_length=
+      event.security_user ? strlen(event.security_user) : 0;
+	event.security_priv_user= ctx->priv_user;
+	event.security_priv_user_length=
+      event.security_priv_user ? strlen(event.security_priv_user) : 0;
+	event.security_ip= ctx->ip;
+	event.security_ip_length=
+      event.security_ip ? strlen(event.security_ip) : 0;
+	event.security_host_or_ip= ctx->host_or_ip;
+	event.security_host_or_ip_length=
+      event.security_host_or_ip ? strlen(event.security_host_or_ip) : 0;
+	event.security_global_access= ctx->master_access;
+	event.security_schema_access= ctx->db_access;
+  }
+
+  if ((str= va_arg(ap, LEX_STRING *)))
+  {
+    event.security_type= str->str;
+    event.security_type_length= str->length;
+  }
+  if ((str= va_arg(ap, LEX_STRING *)))
+  {
+    event.security_schema= str->str;
+    event.security_schema_length= str->length;
+  }
+  if ((str= va_arg(ap, LEX_STRING *)))
+  {
+    event.security_object= str->str;
+    event.security_object_length= str->length;
+  }
+  if ((str= va_arg(ap, LEX_STRING *)))
+  {
+    event.security_element= str->str;
+    event.security_element_length= str->length;
+  }
+  event.security_object_rights= va_arg(ap, ulong);
+  
+  event_class_dispatch(thd, &event);
+}
+
+
+static audit_handler_t audit_handlers[] =
+{
+  /* MYSQL_AUDIT_GENERAL_CLASS */   general_class_handler,
+  /* MYSQL_AUDIT_SECURITY_CLASS */  security_class_handler,
+  NULL
+};
+
+static const uint audit_handlers_count=
+  (sizeof(audit_handlers) / sizeof(audit_handler_t)) - 1;
+
+
+/**
+  Acquire and lock any additional audit plugins as required
+  
+  @param[in] thd
+  @param[in] plugin
+  @param[in] arg
+
+  @retval FALSE Always  
+*/
+
+static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg)
+{
+  uint event_class= *(uint*) arg;
+  uint64 event_class_mask1= (1 << event_class);
+  st_mysql_audit *data= plugin_data(plugin, struct st_mysql_audit *);
+
+  /* Check if this plugin is interested in the event */
+  if (!(data->class_mask[0] & event_class_mask1))
+    return 0;
+  
+  /* Check if we need to initialize the array of acquired plugins */
+  if (unlikely(!thd->audit_class_plugins.buffer))
+  {
+    /* specify some reasonable initialization defaults */
+    my_init_dynamic_array(&thd->audit_class_plugins,
+                          sizeof(plugin_ref), 16, 16);
+  }
+  else
+  {
+    plugin_ref *plugins, *plugins_last;
+	
+	plugins= (plugin_ref*) thd->audit_class_plugins.buffer;
+	plugins_last= plugins + thd->audit_class_plugins.elements;
+	for (; plugins < plugins_last; plugins++)
+	{
+      st_mysql_audit *data2= plugin_data(*plugins, struct st_mysql_audit *);
+
+      /* Check if we already have acquired this plugin */
+	  if (data == data2)
+		return 0;
+	}
+  }
+  
+  /* lock the plugin and add it to the list */
+  plugin= my_plugin_lock(NULL, &plugin);
+  insert_dynamic(&thd->audit_class_plugins, (uchar*) &plugin);
+
+  return 0;
+}
+
+
+/**
+  Notify the audit system of an event
+  
+  @param[in] thd
+  @param[in] event_class
+  @param[in] event_subtype
+  @param[in] error_code
+
+*/
+
+void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype,
+                        int error_code, ...)
+{
+  va_list ap;
+  audit_handler_t *handlers= audit_handlers + event_class;
+  uint64 event_class_mask1= (1 << event_class);
+  
+  DBUG_ASSERT(event_class < audit_handlers_count);
+
+  if (thd && thd->killed == THD::KILL_CONNECTION &&
+      !(thd->audit_class_mask1 & event_class_mask1))
+    thd= NULL;
+
+  /*
+    Check to see if we have acquired the audit plugins for the
+	required audit event classes.
+  */
+  if (thd && !(thd->audit_class_mask1 & event_class_mask1))
+  {
+    plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class);
+    thd->audit_class_mask1|= event_class_mask1;
+  }
+
+  va_start(ap, error_code);  
+  (*handlers)(thd, event_subtype, error_code, ap);
+  va_end(ap);
+}
+
+
+/**
+  Release any resources associated with the current thd.
+  
+  @param[in] thd
+
+*/
+
+void mysql_audit_release(THD *thd)
+{
+  plugin_ref *plugins, *plugins_last;
+  
+  if (!thd || !(thd->audit_class_plugins.elements))
+    return;
+  
+  plugins= (plugin_ref*) thd->audit_class_plugins.buffer;
+  plugins_last= plugins + thd->audit_class_plugins.elements;
+  for (; plugins < plugins_last; plugins++)
+  {
+    st_mysql_audit *data= plugin_data(*plugins, struct st_mysql_audit *);
+	
+    /* Check to see if the plugin has a release method */
+	if (!(data->release_thd))
+	  continue;
+
+    /* Tell the plugin to release its resources */
+	data->release_thd(thd);
+  }
+
+  /* Now we actually unlock the plugins */  
+  plugin_unlock_list(NULL, (plugin_ref*) thd->audit_class_plugins.buffer,
+                     thd->audit_class_plugins.elements);
+  
+  /* Reset the state of thread values */
+  reset_dynamic(&thd->audit_class_plugins);
+  thd->audit_class_mask1= 0;
+}
+
+
+/**
+  Initialize thd variables used by Audit
+  
+  @param[in] thd
+
+*/
+
+void mysql_audit_init_thd(THD *thd)
+{
+  bzero(&thd->audit_class_plugins, sizeof(thd->audit_class_plugins));
+  thd->audit_class_mask1= 0;
+}
+
+
+/**
+  Free thd variables used by Audit
+  
+  @param[in] thd
+  @param[in] plugin
+  @param[in] arg
+
+  @retval FALSE Always  
+*/
+
+void mysql_audit_free_thd(THD *thd)
+{
+  mysql_audit_release(thd);
+  DBUG_ASSERT(thd->audit_class_plugins.elements == 0);
+  delete_dynamic(&thd->audit_class_plugins);
+}
+
+
+static DYNAMIC_ARRAY installed_audit_plugins;
+static pthread_mutex_t LOCK_audit;
+
+
+/**
+  Initialize Audit global variables
+*/
+
+void mysql_audit_initialize()
+{
+  (void) pthread_mutex_init(&LOCK_audit, MY_MUTEX_INIT_FAST);
+  my_init_dynamic_array(&installed_audit_plugins, sizeof(void*), 16, 16);
+}
+
+
+/**
+  Finalize Audit global variables  
+*/
+
+void mysql_audit_finalize()
+{
+  delete_dynamic(&installed_audit_plugins);
+  (void) pthread_mutex_destroy(&LOCK_audit);
+}
+
+
+/**
+  Initialize an Audit plug-in
+  
+  @param[in] plugin
+
+  @retval FALSE  OK
+  @retval TRUE   There was an error.
+*/
+
+int initialize_audit_plugin(st_plugin_int *plugin)
+{
+  st_mysql_audit *data= (st_mysql_audit*) plugin->plugin->info;
+  int rc;
+  
+  if (!data->class_mask || !data->event_notify ||
+      !data->class_mask[0])
+  {
+    sql_print_error("Plugin '%s' has invalid data.",
+                    plugin->name.str);
+    return 1;
+  }
+  
+  if (plugin->plugin->init && plugin->plugin->init(NULL))
+  {
+    sql_print_error("Plugin '%s' init function returned error.",
+                    plugin->name.str);
+    return 1;
+  }
+
+  /* Make the interface info more easily accessible */
+  plugin->data= plugin->plugin->info;
+  
+  pthread_mutex_lock(&LOCK_audit);
+  
+  rc= insert_dynamic(&installed_audit_plugins, (uchar*) &plugin->data);
+
+  /* Add the bits the plugin is interested in to the global mask */
+  mysql_global_audit_mask1|= data->class_mask[0];
+
+  pthread_mutex_unlock(&LOCK_audit);
+  
+  return rc;
+}
+
+
+/**
+  Finalize an Audit plug-in
+  
+  @param[in] plugin
+
+  @retval FALSE  OK
+  @retval TRUE   There was an error.
+*/
+int finalize_audit_plugin(st_plugin_int *plugin)
+{
+  uint64 event_class_mask1= 0;
+  st_mysql_audit **data, **data_last;
+  uint index, index_to_delete= (uint) -1;
+  
+  if (plugin->plugin->deinit && plugin->plugin->deinit(NULL))
+  {
+    DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
+                            plugin->name.str));
+    DBUG_EXECUTE("finalize_audit_plugin", return 1; );
+  }
+  
+  pthread_mutex_lock(&LOCK_audit);
+
+  /* Iterate through all the installed plugins to create new mask */
+  data= (st_mysql_audit**) installed_audit_plugins.buffer;
+  data_last= data + installed_audit_plugins.elements;
+  for (index= 0; data < data_last; data++, index++)
+  {
+    if (plugin->data == *data)
+	  index_to_delete= index;
+	else
+      event_class_mask1|= (*data)->class_mask[0];
+  }
+
+  /* Set the global audit mask */
+  mysql_global_audit_mask1= event_class_mask1;
+
+  /* Remove this plugin from the list */
+  if (likely(index_to_delete != (uint) -1))
+    delete_dynamic_element(&installed_audit_plugins, index_to_delete);
+  else
+  {
+    sql_print_error("Plugin '%s' was not found in installed_audit_plugins",
+                    plugin->name.str);
+  }
+
+  pthread_mutex_unlock(&LOCK_audit);
+
+  return 0;
+}
+
+
+/**
+  Distributes an audit event to plug-ins
+  
+  @param[in] thd
+  @param[in] event
+*/
+
+static void event_class_dispatch(THD *thd, const struct mysql_event *event)
+{
+  uint64 event_class_mask1= (1 << event->event_class);
+  
+  if (thd)
+  {
+	plugin_ref *plugins, *plugins_last;
+
+    /* Use the cached set of audit plugins */
+	plugins= (plugin_ref*) thd->audit_class_plugins.buffer;
+	plugins_last= plugins + thd->audit_class_plugins.elements;
+	for (; plugins < plugins_last; plugins++)
+	{
+      st_mysql_audit *data= plugin_data(*plugins, struct st_mysql_audit *);
+
+      /* Check to see if the plugin is interested in this event */
+	  if (!(data->class_mask[0] & event_class_mask1))
+		continue;
+
+      /* Actually notify the plugin */
+	  data->event_notify(thd, event);
+	}
+  }
+  else
+  {
+    st_mysql_audit **data, **data_last;
+	
+	pthread_mutex_lock(&LOCK_audit);
+
+    /* Use our own list of all audit plugins */
+	data= (st_mysql_audit**) installed_audit_plugins.buffer;
+	data_last= data + installed_audit_plugins.elements;
+	for (; data < data_last; data++)
+	{
+	  if (!((*data)->class_mask[0] & event_class_mask1))
+		continue;
+
+      /* Actually notify the plugin */
+	  (*data)->event_notify(0, event);
+	}
+	
+    pthread_mutex_unlock(&LOCK_audit);
+  }
+}
+
+
+
+
+#else /* EMBEDDED_LIBRARY */
+
+void mysql_audit_initialize()
+{
+}
+
+
+void mysql_audit_finalize()
+{
+}
+
+
+int initialize_audit_plugin(st_plugin_int *plugin)
+{
+  return 1;
+}
+
+int finalize_audit_plugin(st_plugin_int *plugin)
+{
+  return 0;
+}
+
+#endif /* EMBEDDED_LIBRARY */
diff -Nrup a/sql/sql_audit.h b/sql/sql_audit.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/sql_audit.h	2007-11-29 14:40:18 -08:00
@@ -0,0 +1,95 @@
+/* Copyright (C) 2007 MySQL AB
+
+   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
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+
+#ifndef EMBEDDED_LIBRARY
+
+#include <mysql/audit.h>
+
+
+extern uint64 mysql_global_audit_mask1;
+
+
+extern void mysql_audit_initialize();
+extern void mysql_audit_finalize();
+
+
+extern void mysql_audit_init_thd(THD *thd);
+extern void mysql_audit_free_thd(THD *thd);
+
+
+extern void mysql_audit_notify(THD *thd, uint event_class,
+                               uint event_subtype,
+                               int error_code, ...);
+extern void mysql_audit_release(THD *thd);
+
+
+
+					  
+#define MYSQL_AUDIT_GENERAL(thd,event_subtype,rc,time,          \
+                            user,userlen,cmd,cmdlen,            \
+                            query,querylen,clientcs,rows) do {  \
+  if (mysql_global_audit_mask1 & MYSQL_AUDIT_GENERAL_CLASSMASK1)\
+  {                                                             \
+	time_t audit_time= (time);                                  \
+	const char *audit_user= (user), *audit_cmd= (cmd);          \
+	const char *audit_query= (query);                           \
+	uint audit_user_len= (userlen), audit_cmd_len= (cmdlen);    \
+	uint audit_query_len= (querylen);                           \
+	CHARSET_INFO *audit_client_cs= (clientcs);                  \
+    ha_rows audit_rows=(rows);                                  \
+    mysql_audit_notify((thd), MYSQL_AUDIT_GENERAL_CLASS,        \
+                       (event_subtype), (rc), audit_time,       \
+                       audit_user, audit_user_len,              \
+                       audit_cmd, audit_cmd_len,                \
+                       audit_query, audit_query_len,            \
+                       audit_client_cs,audit_rows);             \
+  }                                                             \
+} while (0)
+
+
+
+#define MYSQL_AUDIT_SECURITY(thd,event_subtype,rc,type,schema,  \
+                             object,element,rights) do {        \
+  if (mysql_global_audit_mask1 & MYSQL_AUDIT_SECURITY_CLASSMASK1)\
+  {                                                             \
+    LEX_STRING audit_object_type= {C_STRING_WITH_LEN(type)};    \
+    LEX_STRING *audit_schema= (schema);                         \
+    LEX_STRING *audit_object= (object);                         \
+    LEX_STRING *audit_element= (element);                       \
+    ulong audit_rights= (rights);                               \
+    mysql_audit_notify((thd), MYSQL_AUDIT_SECURITY_CLASS,       \
+                       (event_subtype),(rc),&audit_object_type, \
+                       &audit_schema,&audit_object,             \
+                       &audit_element,audit_rights);            \
+  }                                                             \
+} while (0)
+
+#else /* EMBEDDED_LIBRARY */
+
+/* In EMBEDDED_LIBRARY builds, these do nothing */
+
+#define MYSQL_AUDIT_GENERAL(thd,event_subtype,rc,time,          \
+                            user,userlen,cmd,cmdlen,            \
+                            query,querylen,clientcs,rows) do {  \
+} while (0)
+#define MYSQL_AUDIT_SECURITY(thd,event_subtype,rc,type,schema,  \
+                             object,element,rights) do {        \
+} while (0)
+
+#define mysql_audit_release(thd)  do { } while (0)
+
+
+#endif /* EMBEDDED_LIBRARY */
diff -Nrup a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
--- a/sql/sql_builtin.cc.in	2006-12-30 17:28:54 -08:00
+++ b/sql/sql_builtin.cc.in	2007-11-29 14:40:17 -08:00
@@ -13,6 +13,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
+#include <my_global.h>
 #include <mysql/plugin.h>
 
 typedef struct st_mysql_plugin builtin_plugin[];
diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2007-11-22 11:45:21 -08:00
+++ b/sql/sql_class.cc	2007-11-29 14:40:17 -08:00
@@ -30,6 +30,7 @@
 #include "rpl_record.h"
 #include <my_bitmap.h>
 #include "log_event.h"
+#include "sql_audit.h"
 #include <m_ctype.h>
 #include <sys/stat.h>
 #include <thr_alarm.h>
@@ -428,6 +429,7 @@ THD::THD()
   dbug_sentry=THD_SENTRY_MAGIC;
 #endif
 #ifndef EMBEDDED_LIBRARY
+  mysql_audit_init_thd(this);
   net.vio=0;
 #endif
   client_capabilities= 0;                       // minimalistic client
@@ -768,6 +770,8 @@ THD::~THD()
 #ifndef EMBEDDED_LIBRARY
   if (rli_fake)
     delete rli_fake;
+
+  mysql_audit_free_thd(this);
 #endif
 
   free_root(&main_mem_root, MYF(0));
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2007-11-22 11:45:22 -08:00
+++ b/sql/sql_class.h	2007-11-29 14:40:17 -08:00
@@ -1100,6 +1100,10 @@ public:
   ulong max_client_packet_length;
 
   HASH		handler_tables_hash;
+#ifndef EMBEDDED_LIBRARY
+  DYNAMIC_ARRAY audit_class_plugins;
+  uint64 audit_class_mask1;
+#endif
   /*
     One thread can hold up to one named user-level lock. This variable
     points to a lock object if the lock is present. See item_func.cc and
diff -Nrup a/sql/sql_connect.cc b/sql/sql_connect.cc
--- a/sql/sql_connect.cc	2007-11-13 03:52:18 -08:00
+++ b/sql/sql_connect.cc	2007-11-29 14:40:17 -08:00
@@ -19,6 +19,7 @@
 */
 
 #include "mysql_priv.h"
+#include "sql_audit.h"
 
 #ifdef HAVE_OPENSSL
 /*
@@ -318,6 +319,9 @@ check_user(THD *thd, enum enum_server_co
   DBUG_ENTER("check_user");
   LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
 
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_AUTHENTICATE,0,
+                       "USER",&db_str,0,0,0);
+  
   /*
     Clear thd->db as it points to something, that will be freed when
     connection is closed. We don't want to accidentally free a wrong
@@ -673,6 +677,8 @@ static int check_connection(THD *thd)
 #ifdef SIGNAL_WITH_VIO_CLOSE
   thd->set_active_vio(net->vio);
 #endif
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_CONNECT,0,
+                       "CONNECTION",0,0,0,0);
 
   if (!thd->main_security_ctx.host)         // If TCP/IP connection
   {
@@ -997,6 +1003,10 @@ bool login_connection(THD *thd)
 void end_connection(THD *thd)
 {
   NET *net= &thd->net;
+  
+  MYSQL_AUDIT_SECURITY(thd,MYSQL_AUDIT_SECURITY_DISCONNECT,0,
+                       "CONNECTION",0,0,0,0);
+
   plugin_thdvar_cleanup(thd);
   if (thd->user_connect)
     decrease_user_connections(thd->user_connect);
@@ -1142,9 +1152,11 @@ pthread_handler_t handle_one_connection(
            !(thd->killed == THD::KILL_CONNECTION))
     {
       net->no_send_error= 0;
+      mysql_audit_release(thd);
       if (do_command(thd))
 	break;
     }
+    mysql_audit_release(thd);
     end_connection(thd);
    
 end_thread:
diff -Nrup a/sql/sql_insert.cc b/sql/sql_insert.cc
--- a/sql/sql_insert.cc	2007-11-22 11:45:22 -08:00
+++ b/sql/sql_insert.cc	2007-11-29 14:40:18 -08:00
@@ -61,6 +61,7 @@
 #include "sql_show.h"
 #include "slave.h"
 #include "rpl_mi.h"
+#include "sql_audit.h"
 
 #ifndef EMBEDDED_LIBRARY
 static bool delayed_get_table(THD *thd, TABLE_LIST *table_list);
@@ -2331,6 +2332,7 @@ pthread_handler_t handle_delayed_insert(
       di->thd.mysys_var->current_mutex= &di->mutex;
       di->thd.mysys_var->current_cond= &di->cond;
       THD_SET_PROC_INFO(& (di->thd), "Waiting for INSERT");
+      mysql_audit_release(thd);
 
       DBUG_PRINT("info",("Waiting for someone to insert rows"));
       while (!thd->killed)
@@ -2416,6 +2418,7 @@ pthread_handler_t handle_delayed_insert(
       di->table->file->ha_release_auto_increment();
       mysql_unlock_tables(thd, lock);
       di->group_count=0;
+      mysql_audit_release(thd);
       pthread_mutex_lock(&di->mutex);
     }
     if (di->tables_in_use)
diff -Nrup a/sql/sql_plugin.cc b/sql/sql_plugin.cc
--- a/sql/sql_plugin.cc	2007-11-21 12:19:04 -08:00
+++ b/sql/sql_plugin.cc	2007-11-29 14:40:18 -08:00
@@ -16,6 +16,10 @@
 #include "mysql_priv.h"
 #include <my_pthread.h>
 #include <my_getopt.h>
+
+#include <mysql/ftparser.h>
+#include <mysql/audit.h>
+
 #define REPORT_TO_LOG  1
 #define REPORT_TO_USER 2
 
@@ -42,12 +46,16 @@ const LEX_STRING plugin_type_names[MYSQL
   { C_STRING_WITH_LEN("STORAGE ENGINE") },
   { C_STRING_WITH_LEN("FTPARSER") },
   { C_STRING_WITH_LEN("DAEMON") },
-  { C_STRING_WITH_LEN("INFORMATION SCHEMA") }
+  { C_STRING_WITH_LEN("INFORMATION SCHEMA") },
+  { C_STRING_WITH_LEN("AUDIT") }
 };
 
 extern int initialize_schema_table(st_plugin_int *plugin);
 extern int finalize_schema_table(st_plugin_int *plugin);
 
+extern int initialize_audit_plugin(st_plugin_int *plugin);
+extern int finalize_audit_plugin(st_plugin_int *plugin);
+
 /*
   The number of elements in both plugin_type_initialize and
   plugin_type_deinitialize should equal to the number of plugins
@@ -55,12 +63,14 @@ extern int finalize_schema_table(st_plug
 */
 plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
 {
-  0,ha_initialize_handlerton,0,0,initialize_schema_table
+  0,ha_initialize_handlerton,0,0,initialize_schema_table,
+  initialize_audit_plugin
 };
 
 plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
 {
-  0,ha_finalize_handlerton,0,0,finalize_schema_table
+  0,ha_finalize_handlerton,0,0,finalize_schema_table,
+  finalize_audit_plugin
 };
 
 #ifdef HAVE_DLOPEN
@@ -81,7 +91,8 @@ static int min_plugin_info_interface_ver
   MYSQL_HANDLERTON_INTERFACE_VERSION,
   MYSQL_FTPARSER_INTERFACE_VERSION,
   MYSQL_DAEMON_INTERFACE_VERSION,
-  MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
+  MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
+  MYSQL_AUDIT_INTERFACE_VERSION
 };
 static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
 {
@@ -89,7 +100,8 @@ static int cur_plugin_info_interface_ver
   MYSQL_HANDLERTON_INTERFACE_VERSION,
   MYSQL_FTPARSER_INTERFACE_VERSION,
   MYSQL_DAEMON_INTERFACE_VERSION,
-  MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
+  MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION,
+  MYSQL_AUDIT_INTERFACE_VERSION
 };
 
 static bool initialized= 0;
@@ -174,7 +186,8 @@ public:
   sys_var_pluginvar *cast_pluginvar() { return this; }
   bool is_readonly() const { return plugin_var->flags & PLUGIN_VAR_READONLY; }
   bool check_type(enum_var_type type)
-  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) && type != OPT_GLOBAL; }
+  { return !(plugin_var->flags & PLUGIN_VAR_THDLOCAL) ? (type != OPT_GLOBAL)
+    : ((type == OPT_GLOBAL) && (plugin_var->flags & PLUGIN_VAR_NOGLOBAL)); }
   bool check_update_type(Item_result type);
   SHOW_TYPE show_type();
   uchar* real_value_ptr(THD *thd, enum_var_type type);
@@ -330,6 +343,11 @@ static inline void free_plugin_mem(struc
     my_free((uchar*)p->plugins, MYF(MY_ALLOW_ZERO_PTR));
 }
 
+extern "C" char *mysqld_plugin_path(char *tgt, unsigned int tgt_size,
+                                    const char *name)
+{
+  return strxnmov(tgt, tgt_size - 1, opt_plugin_dir, "/", name, NullS);
+}
 
 static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
 {
@@ -346,7 +364,8 @@ static st_plugin_dl *plugin_dl_add(const
     plugin directory are used (to make this even remotely secure).
   */
   if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) ||
-      check_identifier_name((LEX_STRING *) dl) ||
+      check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN,
+                               system_charset_info, 1) ||
       plugin_dir_len + dl->length + 1 >= FN_REFLEN)
   {
     if (report & REPORT_TO_USER)
@@ -364,7 +383,7 @@ static st_plugin_dl *plugin_dl_add(const
   bzero(&plugin_dl, sizeof(plugin_dl));
   /* Compile dll path */
   dlpathlen=
-    strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) -
+    mysqld_plugin_path(dlpath, sizeof(dlpath), dl->str) -
     dlpath;
   plugin_dl.ref_count= 1;
   /* Open new dll handle */
@@ -1179,9 +1198,7 @@ int plugin_init(int *argc, char **argv, 
   /* Register all dynamic plugins */
   if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
   {
-    if (opt_plugin_load &&
-        plugin_load_list(&tmp_root, argc, argv, opt_plugin_load))
-      goto err;
+    plugin_load_list(&tmp_root, argc, argv, opt_plugin_load);
     if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE))
       plugin_load(&tmp_root, argc, argv);
   }
@@ -1310,27 +1327,23 @@ end:
 */
 static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv)
 {
+  THD thd;
   TABLE_LIST tables;
   TABLE *table;
   READ_RECORD read_record_info;
   int error;
-  THD *new_thd;
+  THD *new_thd= &thd;
 #ifdef EMBEDDED_LIBRARY
   bool table_exists;
 #endif /* EMBEDDED_LIBRARY */
   DBUG_ENTER("plugin_load");
 
-  if (!(new_thd= new THD))
-  {
-    sql_print_error("Can't allocate memory for plugin structures");
-    delete new_thd;
-    DBUG_VOID_RETURN;
-  }
   new_thd->thread_stack= (char*) &tables;
   new_thd->store_globals();
   lex_start(new_thd);
   new_thd->db= my_strdup("mysql", MYF(0));
   new_thd->db_length= 5;
+  bzero((char*) &thd.net, sizeof(thd.net));
   bzero((uchar*)&tables, sizeof(tables));
   tables.alias= tables.table_name= (char*)"plugin";
   tables.lock_type= TL_READ;
@@ -1388,7 +1401,6 @@ static void plugin_load(MEM_ROOT *tmp_ro
   new_thd->version--; // Force close to free memory
 end:
   close_thread_tables(new_thd);
-  delete new_thd;
   /* Remember that we don't have a THD */
   my_pthread_setspecific_ptr(THR_THD, 0);
   DBUG_VOID_RETURN;
@@ -1406,11 +1418,15 @@ static bool plugin_load_list(MEM_ROOT *t
   struct st_plugin_dl *plugin_dl;
   struct st_mysql_plugin *plugin;
   char *p= buffer;
+  bool result= FALSE;
   DBUG_ENTER("plugin_load_list");
   while (list)
   {
     if (p == buffer + sizeof(buffer) - 1)
+    {
+      sql_print_warning("plugin-load argument too long");
       break;
+    }
     switch ((*(p++)= *(list++))) {
     case '\0':
       list= NULL; /* terminate the loop */
@@ -1420,6 +1436,7 @@ static bool plugin_load_list(MEM_ROOT *t
 #endif
     case ';':
       name.str[name.length]= '\0';
+      pthread_mutex_lock(&LOCK_plugin);
       if (str != &dl)  // load all plugins in named module
       {
         dl= name;
@@ -1432,7 +1449,10 @@ static bool plugin_load_list(MEM_ROOT *t
 
             free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
             if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+            {
+              pthread_mutex_unlock(&LOCK_plugin);
               goto error;
+            }
           }
           plugin_dl_del(&dl); // reduce ref count
         }
@@ -1441,8 +1461,12 @@ static bool plugin_load_list(MEM_ROOT *t
       {
         free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
         if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG))
+        {
+          pthread_mutex_unlock(&LOCK_plugin);
           goto error;
+        }
       }
+      pthread_mutex_unlock(&LOCK_plugin);
       name.length= dl.length= 0;
       dl.str= NULL; name.str= p= buffer;
       str= &name;
@@ -1459,12 +1483,12 @@ static bool plugin_load_list(MEM_ROOT *t
       str->length++;
       continue;
     }
-  }
-  DBUG_RETURN(FALSE);
 error:
-  sql_print_error("Couldn't load plugin named '%s' with soname '%s'.",
-                  name.str, dl.str);
-  DBUG_RETURN(TRUE);
+    sql_print_warning("Couldn't load plugin named '%s' with soname '%s'.",
+                      name.str, dl.str);
+    result= TRUE;
+  }
+  DBUG_RETURN(result);
 }
 
 
@@ -1611,7 +1635,7 @@ bool mysql_install_plugin(THD *thd, cons
   TABLE *table;
   int error, argc;
   char *argv[2];
-  struct st_plugin_int *tmp;
+  struct st_plugin_int *tmp= NULL;
   DBUG_ENTER("mysql_install_plugin");
 
   bzero(&tables, sizeof(tables));
@@ -1625,16 +1649,28 @@ bool mysql_install_plugin(THD *thd, cons
     DBUG_RETURN(TRUE);
 
   pthread_mutex_lock(&LOCK_plugin);
-  rw_wrlock(&LOCK_system_variables_hash);
+
+  table->use_all_columns();
+  restore_record(table, s->default_values);
+  table->field[0]->store(name->str, name->length, system_charset_info);
+  table->field[1]->store(dl->str, dl->length, files_charset_info);
+  error= table->file->ha_write_row(table->record[0]);
+  if (error)
+  {
+    table->file->print_error(error, MYF(0));
+    goto err;
+  }
+
   /* handle_options() assumes arg0 (program name) always exists */
   argv[0]= const_cast<char*>(""); // without a cast gcc emits a warning
   argv[1]= 0;
   argc= 1;
+  rw_wrlock(&LOCK_system_variables_hash);
   error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER);
   rw_unlock(&LOCK_system_variables_hash);
 
   if (error || !(tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
-    goto err;
+    goto deinit;
 
   if (plugin_initialize(tmp))
   {
@@ -1643,21 +1679,25 @@ bool mysql_install_plugin(THD *thd, cons
     goto deinit;
   }
 
-  table->use_all_columns();
-  restore_record(table, s->default_values);
+  pthread_mutex_unlock(&LOCK_plugin);
+  DBUG_RETURN(FALSE);
+
+deinit:
   table->field[0]->store(name->str, name->length, system_charset_info);
-  table->field[1]->store(dl->str, dl->length, files_charset_info);
-  error= table->file->ha_write_row(table->record[0]);
-  if (error)
+  if (! table->file->index_read_idx_map(table->record[0], 0,
+                                        (uchar *)table->field[0]->ptr,
+                                        HA_WHOLE_KEY,
+                                        HA_READ_KEY_EXACT))
   {
-    table->file->print_error(error, MYF(0));
-    goto deinit;
+    int error;
+    if ((error= table->file->ha_delete_row(table->record[0])))
+    {
+      table->file->print_error(error, MYF(0));
+    }
   }
 
-  pthread_mutex_unlock(&LOCK_plugin);
-  DBUG_RETURN(FALSE);
-deinit:
-  tmp->state= PLUGIN_IS_DELETED;
+  if (tmp)
+    tmp->state= PLUGIN_IS_DELETED;
   reap_needed= true;
   reap_plugins();
 err:
@@ -1803,6 +1843,7 @@ typedef DECLARE_MYSQL_SYSVAR_BASIC(sysva
 typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_bool_t, my_bool);
 typedef DECLARE_MYSQL_SYSVAR_BASIC(sysvar_str_t, char *);
 typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_str_t, char *);
+typedef DECLARE_MYSQL_THDVAR_BASIC(thdvar_opaque_t, void *);
 
 typedef DECLARE_MYSQL_SYSVAR_TYPELIB(sysvar_enum_t, unsigned long);
 typedef DECLARE_MYSQL_THDVAR_TYPELIB(thdvar_enum_t, unsigned long);
@@ -2176,6 +2217,9 @@ static st_bookmark *register_var(const c
   case PLUGIN_VAR_STR:
     size= sizeof(char*);
     break;
+  case PLUGIN_VAR_OPAQUE:
+    size= sizeof(void*);
+    break;
   default:
     DBUG_ASSERT(0);
     return NULL;
@@ -2875,6 +2919,9 @@ static int construct_options(MEM_ROOT *m
     case PLUGIN_VAR_SET:
       SET_PLUGIN_VAR_RESOLVE((thdvar_set_t *) opt);
       break;
+    case PLUGIN_VAR_OPAQUE:
+      SET_PLUGIN_VAR_RESOLVE((thdvar_opaque_t *) opt);
+      break;
     default:
       sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
                       opt->flags, plugin_name);
@@ -2938,13 +2985,17 @@ static int construct_options(MEM_ROOT *m
       if (!opt->update)
         opt->update= update_func_longlong;
       break;
+	case PLUGIN_VAR_OPAQUE:
+	  /* this type is opaque */
+	  break;
     default:
       sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
                       opt->flags, plugin_name);
       DBUG_RETURN(-1);
     }
 
-    if (opt->flags & PLUGIN_VAR_NOCMDOPT)
+    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
+                    == PLUGIN_VAR_NOCMDOPT)
       continue;
 
     if (!opt->name)
@@ -2954,7 +3005,7 @@ static int construct_options(MEM_ROOT *m
       DBUG_RETURN(-1);
     }
 
-    if (!(v= find_bookmark(name, opt->name, opt->flags)))
+    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
     {
       optnamelen= strlen(opt->name);
       optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
@@ -2962,7 +3013,22 @@ static int construct_options(MEM_ROOT *m
       optnamelen= namelen + optnamelen + 1;
     }
     else
-      optname= (char*) memdup_root(mem_root, v->key + 1, (optnamelen= v->name_len) + 1);
+    {
+      if (!(v= find_bookmark(name, opt->name, opt->flags)))
+      {
+        sql_print_error("Thread local variable '%s' not allocated "
+                        "in plugin '%s'.", opt->name, plugin_name);
+    	DBUG_RETURN(-1);
+      }
+
+      *(int*)(opt + 1)= offset= v->offset;
+
+      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
+        continue;
+
+      optname= (char*) memdup_root(mem_root, v->key + 1, 
+                                   (optnamelen= v->name_len) + 1);
+    }
 
     /* convert '_' to '-' */
     for (p= optname; *p; p++)
@@ -2973,9 +3039,6 @@ static int construct_options(MEM_ROOT *m
     options->comment= opt->comment;
     options->app_type= opt;
     options->id= (options-1)->id + 1;
-
-    if (opt->flags & PLUGIN_VAR_THDLOCAL)
-      *(int*)(opt + 1)= offset= v->offset;
 
     plugin_opt_set_limits(options, opt);
 
diff -Nrup a/storage/myisam/ftdefs.h b/storage/myisam/ftdefs.h
--- a/storage/myisam/ftdefs.h	2007-05-10 02:59:32 -07:00
+++ b/storage/myisam/ftdefs.h	2007-11-29 14:40:18 -08:00
@@ -21,7 +21,7 @@
 #include <m_ctype.h>
 #include <my_tree.h>
 #include <queues.h>
-#include <mysql/plugin.h>
+#include <mysql/ftparser.h>
 
 #define true_word_char(ctype, character) \
                       ((ctype) & (_MY_U | _MY_L | _MY_NMR) || \
diff -Nrup a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
--- a/storage/myisam/ha_myisam.cc	2007-10-25 00:39:55 -07:00
+++ b/storage/myisam/ha_myisam.cc	2007-11-29 14:40:18 -08:00
@@ -20,7 +20,7 @@
 
 #define MYSQL_SERVER 1
 #include "mysql_priv.h"
-#include <mysql/plugin.h>
+#include <mysql/ftparser.h>
 #include <m_ctype.h>
 #include <my_bit.h>
 #include <myisampack.h>
Thread
bk commit into 6.0 tree (acurtis:1.2699) WL#3771antony29 Nov
  • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Sergei Golubchik3 Dec
    • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Antony T Curtis3 Dec
    • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Sergei Golubchik3 Dec
      • Re: bk commit into 6.0 tree (acurtis:1.2699) WL#3771Antony T Curtis3 Dec