Drizzled Public API Documentation

sql_error.cc
00001 /* Copyright (C) 1995-2002 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA */
00015 
00016 /**********************************************************************
00017 This file contains the implementation of error and warnings related
00018 
00019   - Whenever an error or warning occurred, it pushes it to a warning list
00020     that the user can retrieve with SHOW WARNINGS or SHOW ERRORS.
00021 
00022   - For each statement, we return the number of warnings generated from this
00023     command.  Note that this can be different from @@warning_count as
00024     we reset the warning list only for questions that uses a table.
00025     This is done to allow on to do:
00026     INSERT ...;
00027     SELECT @@warning_count;
00028     SHOW WARNINGS;
00029     (If we would reset after each command, we could not retrieve the number
00030      of warnings)
00031 
00032   - When client requests the information using SHOW command, then
00033     server processes from this list and returns back in the form of
00034     resultset.
00035 
00036     Supported syntaxes:
00037 
00038     SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
00039     SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
00040     SELECT @@warning_count, @@error_count;
00041 
00042 ***********************************************************************/
00043 
00044 #include <config.h>
00045 
00046 #include <cstdio>
00047 #include <stdarg.h>
00048 
00049 #include <drizzled/session.h>
00050 #include <drizzled/sql_base.h>
00051 #include <drizzled/item/empty_string.h>
00052 #include <drizzled/item/return_int.h>
00053 #include <drizzled/plugin/client.h>
00054 #include <drizzled/sql_lex.h>
00055 #include <drizzled/system_variables.h>
00056 #include <drizzled/diagnostics_area.h>
00057 
00058 using namespace std;
00059 
00060 namespace drizzled {
00061 
00062 /*
00063   Store a new message in an error object
00064 
00065   This is used to in group_concat() to register how many warnings we actually
00066   got after the query has been executed.
00067 */
00068 void DRIZZLE_ERROR::set_msg(Session *session, const char *msg_arg)
00069 {
00070   msg= session->warn_root.strdup(msg_arg);
00071 }
00072 
00073 /*
00074   Reset all warnings for the thread
00075 
00076   SYNOPSIS
00077     drizzle_reset_errors()
00078     session     Thread handle
00079     force               Reset warnings even if it has been done before
00080 
00081   IMPLEMENTATION
00082     Don't reset warnings if this has already been called for this query.
00083     This may happen if one gets a warning during the parsing stage,
00084     in which case push_warnings() has already called this function.
00085 */
00086 
00087 void drizzle_reset_errors(Session& session, bool force)
00088 {
00089   if (session.getQueryId() != session.getWarningQueryId() || force)
00090   {
00091     session.setWarningQueryId(session.getQueryId());
00092     session.warn_root.free_root(MYF(0));
00093     memset(session.warn_count, 0, sizeof(session.warn_count));
00094     if (force)
00095       session.total_warn_count= 0;
00096     session.main_da().m_warn_list.clear();
00097     session.row_count= 1; // by default point to row 1
00098   }
00099 }
00100 
00101 
00102 /*
00103   Push the warning/error to error list if there is still room in the list
00104 
00105   SYNOPSIS
00106     push_warning()
00107     session     Thread handle
00108     level   Severity of warning (note, warning, error ...)
00109     code    Error number
00110     msg     Clear error message
00111 
00112   RETURN
00113     pointer on DRIZZLE_ERROR object
00114 */
00115 
00116 DRIZZLE_ERROR *push_warning(Session *session, DRIZZLE_ERROR::enum_warning_level level,
00117                             drizzled::error_t code, const char *msg)
00118 {
00119   if (level == DRIZZLE_ERROR::WARN_LEVEL_NOTE && !(session->options & OPTION_SQL_NOTES))
00120   {
00121     return NULL;
00122   }
00123 
00124   if (session->getQueryId() != session->getWarningQueryId())
00125     drizzle_reset_errors(*session, false);
00126   session->got_warning= 1;
00127 
00128   /* Abort if we are using strict mode and we are not using IGNORE */
00129   if ((int) level >= (int) DRIZZLE_ERROR::WARN_LEVEL_WARN &&
00130       session->abortOnWarning())
00131   {
00132     /* Avoid my_message() calling push_warning */
00133     bool no_warnings_for_error= session->no_warnings_for_error;
00134 
00135     session->no_warnings_for_error= 1;
00136 
00137     session->setKilled(Session::KILL_BAD_DATA);
00138     my_message(code, msg, MYF(0));
00139 
00140     session->no_warnings_for_error= no_warnings_for_error;
00141     /* Store error in error list (as my_message() didn't do it) */
00142     level= DRIZZLE_ERROR::WARN_LEVEL_ERROR;
00143   }
00144 
00145   DRIZZLE_ERROR *err= NULL;
00146   if (session->main_da().m_warn_list.size() < session->variables.max_error_count)
00147   {
00148     /* We have to use warn_root, as mem_root is freed after each query */
00149     err= new (session->warn_root) DRIZZLE_ERROR(session, code, level, msg);
00150     session->main_da().m_warn_list.push_back(err);
00151   }
00152   session->warn_count[level]++;
00153   session->total_warn_count++;
00154 
00155   return err;
00156 }
00157 
00158 /*
00159   Push the warning/error to error list if there is still room in the list
00160 
00161   SYNOPSIS
00162     push_warning_printf()
00163     session     Thread handle
00164     level   Severity of warning (note, warning, error ...)
00165     code    Error number
00166     msg     Clear error message
00167 */
00168 
00169 void push_warning_printf(Session *session, DRIZZLE_ERROR::enum_warning_level level,
00170        drizzled::error_t code, const char *format, ...)
00171 {
00172   va_list args;
00173   char    warning[ERRMSGSIZE+20];
00174 
00175   va_start(args,format);
00176   vsnprintf(warning, sizeof(warning), format, args);
00177   va_end(args);
00178   push_warning(session, level, code, warning);
00179 }
00180 
00181 
00182 /*
00183   Send all notes, errors or warnings to the client in a result set
00184 
00185   SYNOPSIS
00186     show_warnings()
00187     session     Thread handler
00188     levels_to_show  Bitmap for which levels to show
00189 
00190   DESCRIPTION
00191     Takes into account the current LIMIT
00192 
00193   RETURN VALUES
00194     false ok
00195     true  Error sending data to client
00196 */
00197 
00198 const lex_string_t warning_level_names[]=
00199 {
00200   { C_STRING_WITH_LEN("Note") },
00201   { C_STRING_WITH_LEN("Warning") },
00202   { C_STRING_WITH_LEN("Error") },
00203   { C_STRING_WITH_LEN("?") }
00204 };
00205 
00206 bool show_warnings(Session *session, bitset<DRIZZLE_ERROR::NUM_ERRORS> &levels_to_show)
00207 {
00208   List<Item> field_list;
00209 
00210   field_list.push_back(new Item_empty_string("Level", 7));
00211   field_list.push_back(new Item_return_int("Code",4, DRIZZLE_TYPE_LONG));
00212   field_list.push_back(new Item_empty_string("Message",DRIZZLE_ERRMSG_SIZE));
00213 
00214   session->getClient()->sendFields(field_list);
00215 
00216   Select_Lex *sel= &session->lex().select_lex;
00217   Select_Lex_Unit *unit= &session->lex().unit;
00218   ha_rows idx= 0;
00219 
00220   unit->set_limit(sel);
00221 
00222   BOOST_FOREACH(DRIZZLE_ERROR* err, session->main_da().m_warn_list)
00223   {
00224     /* Skip levels that the user is not interested in */
00225     if (! levels_to_show.test(err->level))
00226       continue;
00227     if (++idx <= unit->offset_limit_cnt)
00228       continue;
00229     if (idx > unit->select_limit_cnt)
00230       break;
00231     session->getClient()->store(warning_level_names[err->level]);
00232     session->getClient()->store((uint32_t) err->code);
00233     session->getClient()->store(err->msg, strlen(err->msg));
00234     if (session->getClient()->flush())
00235       return true;
00236   }
00237   session->my_eof();
00238   return false;
00239 }
00240 
00241 } /* namespace drizzled */