~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/parser.cc

  • Committer: Monty Taylor
  • Date: 2011-01-26 19:15:55 UTC
  • mto: This revision was merged to the branch mainline in revision 2126.
  • Revision ID: mordred@inaugust.com-20110126191555-nq5nnzyscvngsip2
Turns on -fvisibility=hidden by default. Symbols intended to be used by
plugins need to be marked with DRIZZLED_API.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2010 Brian Aker
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
#include "config.h"
 
22
 
 
23
#include <drizzled/parser.h>
 
24
 
 
25
namespace drizzled
 
26
{
 
27
namespace parser
 
28
{
 
29
 
 
30
/**
 
31
  Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
 
32
  See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
 
33
  This function returns the proper item for the SQL expression
 
34
  <code>left [NOT] IN ( expr )</code>
 
35
  @param session the current thread
 
36
  @param left the in predicand
 
37
  @param equal true for IN predicates, false for NOT IN predicates
 
38
  @param expr first and only expression of the in value list
 
39
  @return an expression representing the IN predicate.
 
40
*/
 
41
 
 
42
Item* handle_sql2003_note184_exception(Session *session, Item* left, bool equal, Item *expr)
 
43
{
 
44
  /*
 
45
    Relevant references for this issue:
 
46
    - SQL:2003, Part 2, section 8.4 <in predicate>, page 383,
 
47
    - SQL:2003, Part 2, section 7.2 <row value expression>, page 296,
 
48
    - SQL:2003, Part 2, section 6.3 <value expression primary>, page 174,
 
49
    - SQL:2003, Part 2, section 7.15 <subquery>, page 370,
 
50
    - SQL:2003 Feature F561, "Full value expressions".
 
51
 
 
52
    The exception in SQL:2003 Note 184 means:
 
53
    Item_singlerow_subselect, which corresponds to a <scalar subquery>,
 
54
    should be re-interpreted as an Item_in_subselect, which corresponds
 
55
    to a <table subquery> when used inside an <in predicate>.
 
56
 
 
57
    Our reading of Note 184 is reccursive, so that all:
 
58
    - IN (( <subquery> ))
 
59
    - IN ((( <subquery> )))
 
60
    - IN '('^N <subquery> ')'^N
 
61
    - etc
 
62
    should be interpreted as a <table subquery>, no matter how deep in the
 
63
    expression the <subquery> is.
 
64
  */
 
65
 
 
66
  Item *result;
 
67
 
 
68
  if (expr->type() == Item::SUBSELECT_ITEM)
 
69
  {
 
70
    Item_subselect *expr2 = (Item_subselect*) expr;
 
71
 
 
72
    if (expr2->substype() == Item_subselect::SINGLEROW_SUBS)
 
73
    {
 
74
      Item_singlerow_subselect *expr3 = (Item_singlerow_subselect*) expr2;
 
75
      Select_Lex *subselect;
 
76
 
 
77
      /*
 
78
        Implement the mandated change, by altering the semantic tree:
 
79
          left IN Item_singlerow_subselect(subselect)
 
80
        is modified to
 
81
          left IN (subselect)
 
82
        which is represented as
 
83
          Item_in_subselect(left, subselect)
 
84
      */
 
85
      subselect= expr3->invalidate_and_restore_select_lex();
 
86
      result= new (session->mem_root) Item_in_subselect(left, subselect);
 
87
 
 
88
      if (! equal)
 
89
        result = negate_expression(session, result);
 
90
 
 
91
      return(result);
 
92
    }
 
93
  }
 
94
 
 
95
  if (equal)
 
96
    result= new (session->mem_root) Item_func_eq(left, expr);
 
97
  else
 
98
    result= new (session->mem_root) Item_func_ne(left, expr);
 
99
 
 
100
  return(result);
 
101
}
 
102
 
 
103
/**
 
104
   @brief Creates a new Select_Lex for a UNION branch.
 
105
 
 
106
   Sets up and initializes a Select_Lex structure for a query once the parser
 
107
   discovers a UNION token. The current Select_Lex is pushed on the stack and
 
108
   the new Select_Lex becomes the current one..=
 
109
 
 
110
   @lex The parser state.
 
111
 
 
112
   @is_union_distinct True if the union preceding the new select statement
 
113
   uses UNION DISTINCT.
 
114
 
 
115
   @return <code>false</code> if successful, <code>true</code> if an error was
 
116
   reported. In the latter case parsing should stop.
 
117
 */
 
118
bool add_select_to_union_list(Session *session, LEX *lex, bool is_union_distinct)
 
119
{
 
120
  if (lex->result)
 
121
  {
 
122
    /* Only the last SELECT can have  INTO...... */
 
123
    my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
 
124
    return true;
 
125
  }
 
126
  if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
 
127
  {
 
128
    my_parse_error(session->m_lip);
 
129
    return true;
 
130
  }
 
131
  /* This counter shouldn't be incremented for UNION parts */
 
132
  lex->nest_level--;
 
133
  if (new_select(lex, 0))
 
134
    return true;
 
135
  init_select(lex);
 
136
  lex->current_select->linkage=UNION_TYPE;
 
137
  if (is_union_distinct) /* UNION DISTINCT - remember position */
 
138
    lex->current_select->master_unit()->union_distinct=
 
139
      lex->current_select;
 
140
  return false;
 
141
}
 
142
 
 
143
/**
 
144
   @brief Initializes a Select_Lex for a query within parentheses (aka
 
145
   braces).
 
146
 
 
147
   @return false if successful, true if an error was reported. In the latter
 
148
   case parsing should stop.
 
149
 */
 
150
bool setup_select_in_parentheses(Session *session, LEX *lex)
 
151
{
 
152
  Select_Lex * sel= lex->current_select;
 
153
  if (sel->set_braces(1))
 
154
  {
 
155
    my_parse_error(session->m_lip);
 
156
    return true;
 
157
  }
 
158
  if (sel->linkage == UNION_TYPE &&
 
159
      !sel->master_unit()->first_select()->braces &&
 
160
      sel->master_unit()->first_select()->linkage ==
 
161
      UNION_TYPE)
 
162
  {
 
163
    my_parse_error(session->m_lip);
 
164
    return true;
 
165
  }
 
166
  if (sel->linkage == UNION_TYPE &&
 
167
      sel->olap != UNSPECIFIED_OLAP_TYPE &&
 
168
      sel->master_unit()->fake_select_lex)
 
169
  {
 
170
    my_error(ER_WRONG_USAGE, MYF(0), "CUBE/ROLLUP", "ORDER BY");
 
171
    return true;
 
172
  }
 
173
  /* select in braces, can't contain global parameters */
 
174
  if (sel->master_unit()->fake_select_lex)
 
175
    sel->master_unit()->global_parameters=
 
176
      sel->master_unit()->fake_select_lex;
 
177
  return false;
 
178
}
 
179
 
 
180
Item* reserved_keyword_function(Session *session, const std::string &name, List<Item> *item_list)
 
181
{
 
182
  const plugin::Function *udf= plugin::Function::get(name.c_str(), name.length());
 
183
  Item *item= NULL;
 
184
 
 
185
  if (udf)
 
186
  {
 
187
    item= Create_udf_func::s_singleton.create(session, udf, item_list);
 
188
  } else {
 
189
    my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", name.c_str());
 
190
  }
 
191
 
 
192
  return item;
 
193
}
 
194
 
 
195
/**
 
196
  @brief Push an error message into MySQL error stack with line
 
197
  and position information.
 
198
 
 
199
  This function provides semantic action implementers with a way
 
200
  to push the famous "You have a syntax error near..." error
 
201
  message into the error stack, which is normally produced only if
 
202
  a parse error is discovered internally by the Bison generated
 
203
  parser.
 
204
*/
 
205
void my_parse_error(Lex_input_stream *lip)
 
206
{
 
207
  assert(lip);
 
208
 
 
209
  const char *yytext= lip->get_tok_start();
 
210
  /* Push an error into the error stack */
 
211
  my_printf_error(ER_PARSE_ERROR,  ER(ER_PARSE_ERROR), MYF(0), ER(ER_SYNTAX_ERROR),
 
212
                  (yytext ? yytext : ""),
 
213
                  lip->yylineno);
 
214
}
 
215
 
 
216
void my_parse_error(const char *message)
 
217
{
 
218
  my_printf_error(ER_PARSE_ERROR_UNKNOWN, ER(ER_PARSE_ERROR_UNKNOWN), MYF(0), message);
 
219
}
 
220
 
 
221
bool check_reserved_words(LEX_STRING *name)
 
222
{
 
223
  if (!my_strcasecmp(system_charset_info, name->str, "GLOBAL") ||
 
224
      !my_strcasecmp(system_charset_info, name->str, "LOCAL") ||
 
225
      !my_strcasecmp(system_charset_info, name->str, "SESSION"))
 
226
    return true;
 
227
 
 
228
  return false;
 
229
}
 
230
 
 
231
 
 
232
/**
 
233
  @brief Bison callback to report a syntax/OOM error
 
234
 
 
235
  This function is invoked by the bison-generated parser
 
236
  when a syntax error, a parse error or an out-of-memory
 
237
  condition occurs. This function is not invoked when the
 
238
  parser is requested to abort by semantic action code
 
239
  by means of YYABORT or YYACCEPT macros. This is why these
 
240
  macros should not be used (use DRIZZLE_YYABORT/DRIZZLE_YYACCEPT
 
241
  instead).
 
242
 
 
243
  The parser will abort immediately after invoking this callback.
 
244
 
 
245
  This function is not for use in semantic actions and is internal to
 
246
  the parser, as it performs some pre-return cleanup.
 
247
  In semantic actions, please use parser::my_parse_error or my_error to
 
248
  push an error into the error stack and DRIZZLE_YYABORT
 
249
  to abort from the parser.
 
250
*/
 
251
void errorOn(const char *s)
 
252
{
 
253
  Session *session= current_session;
 
254
 
 
255
  /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
 
256
  if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
 
257
  {
 
258
    parser::my_parse_error(session->m_lip);
 
259
  }
 
260
  else
 
261
  {
 
262
    parser::my_parse_error(s);
 
263
  }
 
264
}
 
265
 
 
266
bool buildOrderBy(Session *session)
 
267
{
 
268
  Select_Lex *sel= session->getLex()->current_select;
 
269
  Select_Lex_Unit *unit= sel-> master_unit();
 
270
 
 
271
  if (sel->linkage != GLOBAL_OPTIONS_TYPE &&
 
272
      sel->olap != UNSPECIFIED_OLAP_TYPE &&
 
273
      (sel->linkage != UNION_TYPE || sel->braces))
 
274
  {
 
275
    my_error(ER_WRONG_USAGE, MYF(0),
 
276
             "CUBE/ROLLUP", "ORDER BY");
 
277
    return false;
 
278
  }
 
279
 
 
280
  if (session->getLex()->sql_command != SQLCOM_ALTER_TABLE && !unit->fake_select_lex)
 
281
  {
 
282
    /*
 
283
      A query of the of the form (SELECT ...) ORDER BY order_list is
 
284
      executed in the same way as the query
 
285
      SELECT ... ORDER BY order_list
 
286
      unless the SELECT construct contains ORDER BY or LIMIT clauses.
 
287
      Otherwise we create a fake Select_Lex if it has not been created
 
288
      yet.
 
289
    */
 
290
    Select_Lex *first_sl= unit->first_select();
 
291
    if (!unit->is_union() &&
 
292
        (first_sl->order_list.elements ||
 
293
         first_sl->select_limit) &&           
 
294
        unit->add_fake_select_lex(session->getLex()->session))
 
295
    {
 
296
      return false;
 
297
    }
 
298
  }
 
299
 
 
300
  return true;
 
301
}
 
302
 
 
303
void buildEngineOption(Session *session, const char *key, const LEX_STRING &value)
 
304
{
 
305
  message::Engine::Option *opt= session->getLex()->table()->mutable_engine()->add_options();
 
306
  opt->set_name(key);
 
307
  opt->set_state(value.str, value.length);
 
308
}
 
309
 
 
310
void buildEngineOption(Session *session, const char *key, uint64_t value)
 
311
{
 
312
  drizzled::message::Engine::Option *opt= session->getLex()->table()->mutable_engine()->add_options();
 
313
  opt->set_name(key);
 
314
  opt->set_state(boost::lexical_cast<std::string>(value));
 
315
}
 
316
 
 
317
void buildSchemaOption(Session *session, const char *key, const LEX_STRING &value)
 
318
{
 
319
  statement::CreateSchema *statement= (statement::CreateSchema *)session->getLex()->statement;
 
320
  message::Engine::Option *opt= statement->schema_message.mutable_engine()->add_options();
 
321
  opt->set_name(key);
 
322
  opt->set_state(value.str, value.length);
 
323
}
 
324
 
 
325
void buildSchemaOption(Session *session, const char *key, uint64_t value)
 
326
{
 
327
  statement::CreateSchema *statement= (statement::CreateSchema *)session->getLex()->statement;
 
328
  message::Engine::Option *opt= statement->schema_message.mutable_engine()->add_options();
 
329
  opt->set_name(key);
 
330
  opt->set_state(boost::lexical_cast<std::string>(value));
 
331
}
 
332
 
 
333
bool checkFieldIdent(Session *session, const LEX_STRING &schema_name, const LEX_STRING &table_name)
 
334
{
 
335
  TableList *table= reinterpret_cast<TableList*>(session->getLex()->current_select->table_list.first);
 
336
 
 
337
  if (schema_name.length)
 
338
  {
 
339
    if (my_strcasecmp(table_alias_charset, schema_name.str, table->getSchemaName()))
 
340
    {
 
341
      my_error(ER_WRONG_DB_NAME, MYF(0), schema_name.str);
 
342
      return false;
 
343
    }
 
344
  }
 
345
 
 
346
  if (my_strcasecmp(table_alias_charset, table_name.str,
 
347
                    table->getTableName()))
 
348
  {
 
349
    my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
 
350
    return false;
 
351
  }
 
352
 
 
353
  return true;
 
354
}
 
355
 
 
356
Item *buildIdent(Session *session,
 
357
                 const LEX_STRING &schema_name,
 
358
                 const LEX_STRING &table_name,
 
359
                 const LEX_STRING &field_name)
 
360
{
 
361
  Select_Lex *sel= session->getLex()->current_select;
 
362
 
 
363
  if (sel->no_table_names_allowed)
 
364
  {
 
365
    my_error(ER_TABLENAME_NOT_ALLOWED_HERE,
 
366
             MYF(0), table_name.str, session->where);
 
367
  }
 
368
 
 
369
  Item *item= (sel->parsing_place != IN_HAVING or
 
370
               sel->get_in_sum_expr() > 0) ?
 
371
    (Item*) new Item_field(session->getLex()->current_context(), schema_name.str, table_name.str, field_name.str) :
 
372
    (Item*) new Item_ref(session->getLex()->current_context(), schema_name.str, table_name.str, field_name.str);
 
373
 
 
374
  return item;
 
375
}
 
376
 
 
377
} // namespace parser
 
378
} // namespace drizzled