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 
00056 using namespace std;
00057 
00058 namespace drizzled
00059 {
00060 
00061 /*
00062   Store a new message in an error object
00063 
00064   This is used to in group_concat() to register how many warnings we actually
00065   got after the query has been executed.
00066 */
00067 void DRIZZLE_ERROR::set_msg(Session *session, const char *msg_arg)
00068 {
00069   msg= session->warn_root.strdup_root(msg_arg);
00070 }
00071 
00072 /*
00073   Reset all warnings for the thread
00074 
00075   SYNOPSIS
00076     drizzle_reset_errors()
00077     session     Thread handle
00078     force               Reset warnings even if it has been done before
00079 
00080   IMPLEMENTATION
00081     Don't reset warnings if this has already been called for this query.
00082     This may happen if one gets a warning during the parsing stage,
00083     in which case push_warnings() has already called this function.
00084 */
00085 
00086 void drizzle_reset_errors(Session *session, bool force)
00087 {
00088   if (session->getQueryId() != session->getWarningQueryId() || force)
00089   {
00090     session->setWarningQueryId(session->getQueryId());
00091     session->warn_root.free_root(MYF(0));
00092     memset(session->warn_count, 0, sizeof(session->warn_count));
00093     if (force)
00094       session->total_warn_count= 0;
00095     session->warn_list.clear();
00096     session->row_count= 1; // by default point to row 1
00097   }
00098   return;
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   DRIZZLE_ERROR *err= 0;
00120 
00121   if (level == DRIZZLE_ERROR::WARN_LEVEL_NOTE && !(session->options & OPTION_SQL_NOTES))
00122   {
00123     return NULL;
00124   }
00125 
00126   if (session->getQueryId() != session->getWarningQueryId())
00127     drizzle_reset_errors(session, 0);
00128   session->got_warning= 1;
00129 
00130   /* Abort if we are using strict mode and we are not using IGNORE */
00131   if ((int) level >= (int) DRIZZLE_ERROR::WARN_LEVEL_WARN &&
00132       session->abortOnWarning())
00133   {
00134     /* Avoid my_message() calling push_warning */
00135     bool no_warnings_for_error= session->no_warnings_for_error;
00136 
00137     session->no_warnings_for_error= 1;
00138 
00139     session->setKilled(Session::KILL_BAD_DATA);
00140     my_message(code, msg, MYF(0));
00141 
00142     session->no_warnings_for_error= no_warnings_for_error;
00143     /* Store error in error list (as my_message() didn't do it) */
00144     level= DRIZZLE_ERROR::WARN_LEVEL_ERROR;
00145   }
00146 
00147   if (session->handle_error(code, msg, level))
00148     return NULL;
00149 
00150   if (session->warn_list.size() < session->variables.max_error_count)
00151   {
00152     /* We have to use warn_root, as mem_root is freed after each query */
00153     if ((err= new (&session->warn_root) DRIZZLE_ERROR(session, code, level, msg)))
00154     {
00155       session->warn_list.push_back(err, &session->warn_root);
00156     }
00157   }
00158   session->warn_count[(uint32_t) level]++;
00159   session->total_warn_count++;
00160 
00161   return err;
00162 }
00163 
00164 /*
00165   Push the warning/error to error list if there is still room in the list
00166 
00167   SYNOPSIS
00168     push_warning_printf()
00169     session     Thread handle
00170     level   Severity of warning (note, warning, error ...)
00171     code    Error number
00172     msg     Clear error message
00173 */
00174 
00175 void push_warning_printf(Session *session, DRIZZLE_ERROR::enum_warning_level level,
00176        drizzled::error_t code, const char *format, ...)
00177 {
00178   va_list args;
00179   char    warning[ERRMSGSIZE+20];
00180 
00181   va_start(args,format);
00182   vsnprintf(warning, sizeof(warning), format, args);
00183   va_end(args);
00184   push_warning(session, level, code, warning);
00185 }
00186 
00187 
00188 /*
00189   Send all notes, errors or warnings to the client in a result set
00190 
00191   SYNOPSIS
00192     show_warnings()
00193     session     Thread handler
00194     levels_to_show  Bitmap for which levels to show
00195 
00196   DESCRIPTION
00197     Takes into account the current LIMIT
00198 
00199   RETURN VALUES
00200     false ok
00201     true  Error sending data to client
00202 */
00203 
00204 const LEX_STRING warning_level_names[]=
00205 {
00206   { C_STRING_WITH_LEN("Note") },
00207   { C_STRING_WITH_LEN("Warning") },
00208   { C_STRING_WITH_LEN("Error") },
00209   { C_STRING_WITH_LEN("?") }
00210 };
00211 
00212 bool show_warnings(Session *session,
00213                    bitset<DRIZZLE_ERROR::NUM_ERRORS> &levels_to_show)
00214 {
00215   List<Item> field_list;
00216 
00217   field_list.push_back(new Item_empty_string("Level", 7));
00218   field_list.push_back(new Item_return_int("Code",4, DRIZZLE_TYPE_LONG));
00219   field_list.push_back(new Item_empty_string("Message",DRIZZLE_ERRMSG_SIZE));
00220 
00221   if (session->getClient()->sendFields(&field_list))
00222     return true;
00223 
00224   DRIZZLE_ERROR *err;
00225   Select_Lex *sel= &session->lex().select_lex;
00226   Select_Lex_Unit *unit= &session->lex().unit;
00227   ha_rows idx= 0;
00228 
00229   unit->set_limit(sel);
00230 
00231   List<DRIZZLE_ERROR>::iterator it(session->warn_list.begin());
00232   while ((err= it++))
00233   {
00234     /* Skip levels that the user is not interested in */
00235     if (! levels_to_show.test(err->level))
00236       continue;
00237     if (++idx <= unit->offset_limit_cnt)
00238       continue;
00239     if (idx > unit->select_limit_cnt)
00240       break;
00241     session->getClient()->store(warning_level_names[err->level].str,
00242                                 warning_level_names[err->level].length);
00243     session->getClient()->store((uint32_t) err->code);
00244     session->getClient()->store(err->msg, strlen(err->msg));
00245     if (session->getClient()->flush())
00246       return(true);
00247   }
00248   session->my_eof();
00249   return(false);
00250 }
00251 
00252 } /* namespace drizzled */