~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_parse.cc

  • Committer: Monty Taylor
  • Date: 2011-02-13 17:26:39 UTC
  • mfrom: (2157.2.2 give-in-to-pkg-config)
  • mto: This revision was merged to the branch mainline in revision 2166.
  • Revision ID: mordred@inaugust.com-20110213172639-nhy7i72sfhoq13ms
Merged in pkg-config fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
#define DRIZZLE_LEX 1
19
19
 
 
20
#include "drizzled/item/num.h"
 
21
#include "drizzled/abort_exception.h"
20
22
#include <drizzled/my_hash.h>
21
23
#include <drizzled/error.h>
22
24
#include <drizzled/nested_join.h>
32
34
#include <drizzled/item/cmpfunc.h>
33
35
#include <drizzled/item/null.h>
34
36
#include <drizzled/session.h>
 
37
#include <drizzled/session/cache.h>
35
38
#include <drizzled/sql_load.h>
36
39
#include <drizzled/lock.h>
37
40
#include <drizzled/select_send.h>
39
42
#include <drizzled/statement.h>
40
43
#include <drizzled/statement/alter_table.h>
41
44
#include "drizzled/probes.h"
42
 
#include "drizzled/session_list.h"
43
45
#include "drizzled/global_charset_info.h"
44
46
 
45
47
#include "drizzled/plugin/logging.h"
49
51
#include "drizzled/optimizer/explain_plan.h"
50
52
#include "drizzled/pthread_globals.h"
51
53
#include "drizzled/plugin/event_observer.h"
 
54
#include "drizzled/visibility.h"
52
55
 
53
56
#include <limits.h>
54
57
 
67
70
/* Prototypes */
68
71
bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
69
72
static bool parse_sql(Session *session, Lex_input_stream *lip);
70
 
void mysql_parse(Session *session, const char *inBuf, uint32_t length);
 
73
void parse(Session *session, const char *inBuf, uint32_t length);
71
74
 
72
75
/**
73
76
  @defgroup Runtime_Environment Runtime Environment
77
80
extern size_t my_thread_stack_size;
78
81
extern const CHARSET_INFO *character_set_filesystem;
79
82
 
80
 
const LEX_STRING command_name[COM_END+1]={
81
 
  { C_STRING_WITH_LEN("Sleep") },
82
 
  { C_STRING_WITH_LEN("Quit") },
83
 
  { C_STRING_WITH_LEN("Init DB") },
84
 
  { C_STRING_WITH_LEN("Query") },
85
 
  { C_STRING_WITH_LEN("Shutdown") },
86
 
  { C_STRING_WITH_LEN("Connect") },
87
 
  { C_STRING_WITH_LEN("Ping") },
88
 
  { C_STRING_WITH_LEN("Error") }  // Last command number
 
83
namespace
 
84
{
 
85
 
 
86
static const std::string command_name[COM_END+1]={
 
87
  "Sleep",
 
88
  "Quit",
 
89
  "Init DB",
 
90
  "Query",
 
91
  "Shutdown",
 
92
  "Connect",
 
93
  "Ping",
 
94
  "Error"  // Last command number
89
95
};
90
96
 
 
97
}
 
98
 
91
99
const char *xa_state_names[]={
92
100
  "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
93
101
};
106
114
*/
107
115
bitset<CF_BIT_SIZE> sql_command_flags[SQLCOM_END+1];
108
116
 
 
117
const std::string &getCommandName(const enum_server_command& command)
 
118
{
 
119
  return command_name[command];
 
120
}
 
121
 
109
122
void init_update_queries(void)
110
123
{
111
124
  uint32_t x;
187
200
    query_id.next();
188
201
  }
189
202
 
190
 
  /* TODO: set session->lex->sql_command to SQLCOM_END here */
 
203
  /* @todo set session->lex->sql_command to SQLCOM_END here */
191
204
 
192
205
  plugin::Logging::preDo(session);
193
206
  if (unlikely(plugin::EventObserver::beforeStatement(*session)))
208
221
 
209
222
    string tmp(packet, packet_length);
210
223
 
211
 
    SchemaIdentifier identifier(tmp);
 
224
    identifier::Schema identifier(tmp);
212
225
 
213
 
    if (not mysql_change_db(session, identifier))
 
226
    if (not change_db(session, identifier))
214
227
    {
215
228
      session->my_ok();
216
229
    }
222
235
      break;                                    // fatal error is set
223
236
    DRIZZLE_QUERY_START(session->getQueryString()->c_str(),
224
237
                        session->thread_id,
225
 
                        const_cast<const char *>(session->db.empty() ? "" : session->db.c_str()));
 
238
                        const_cast<const char *>(session->schema()->c_str()));
226
239
 
227
 
    plugin::QueryRewriter::rewriteQuery(session->getSchema(), session->getQueryString());
228
 
    mysql_parse(session, session->getQueryString()->c_str(), session->getQueryString()->length());
 
240
    parse(session, session->getQueryString()->c_str(), session->getQueryString()->length());
229
241
 
230
242
    break;
231
243
  }
258
270
  /* If commit fails, we should be able to reset the OK status. */
259
271
  session->main_da.can_overwrite_status= true;
260
272
  TransactionServices &transaction_services= TransactionServices::singleton();
261
 
  transaction_services.autocommitOrRollback(session, session->is_error());
 
273
  transaction_services.autocommitOrRollback(*session, session->is_error());
262
274
  session->main_da.can_overwrite_status= false;
263
275
 
264
276
  session->transaction.stmt.reset();
283
295
  {
284
296
  case Diagnostics_area::DA_ERROR:
285
297
    /* The query failed, send error to log and abort bootstrap. */
286
 
    session->client->sendError(session->main_da.sql_errno(),
 
298
    session->getClient()->sendError(session->main_da.sql_errno(),
287
299
                               session->main_da.message());
288
300
    break;
289
301
 
290
302
  case Diagnostics_area::DA_EOF:
291
 
    session->client->sendEOF();
 
303
    session->getClient()->sendEOF();
292
304
    break;
293
305
 
294
306
  case Diagnostics_area::DA_OK:
295
 
    session->client->sendOK();
 
307
    session->getClient()->sendOK();
296
308
    break;
297
309
 
298
310
  case Diagnostics_area::DA_DISABLED:
300
312
 
301
313
  case Diagnostics_area::DA_EMPTY:
302
314
  default:
303
 
    session->client->sendOK();
 
315
    session->getClient()->sendOK();
304
316
    break;
305
317
  }
306
318
 
430
442
    true        Error
431
443
*/
432
444
 
433
 
static int mysql_execute_command(Session *session)
 
445
static int execute_command(Session *session)
434
446
{
435
447
  bool res= false;
436
448
  LEX  *lex= session->lex;
476
488
 
477
489
  assert(session->transaction.stmt.hasModifiedNonTransData() == false);
478
490
 
 
491
  if (! (session->server_status & SERVER_STATUS_AUTOCOMMIT)
 
492
      && ! session->inTransaction()
 
493
      && lex->statement->isTransactional())
 
494
  {
 
495
    if (session->startTransaction() == false)
 
496
    {
 
497
      my_error(drizzled::ER_UNKNOWN_ERROR, MYF(0));
 
498
      return true;
 
499
    }
 
500
  }
 
501
 
479
502
  /* now we are ready to execute the statement */
480
503
  res= lex->statement->execute();
481
504
  session->set_proc_info("query end");
504
527
      param->select_limit=
505
528
        new Item_int((uint64_t) session->variables.select_limit);
506
529
  }
 
530
 
 
531
  if (all_tables
 
532
      && ! (session->server_status & SERVER_STATUS_AUTOCOMMIT)
 
533
      && ! session->inTransaction()
 
534
      && ! lex->statement->isShow())
 
535
  {
 
536
    if (session->startTransaction() == false)
 
537
    {
 
538
      my_error(drizzled::ER_UNKNOWN_ERROR, MYF(0));
 
539
      return true;
 
540
    }
 
541
  }
 
542
 
507
543
  if (not (res= session->openTablesLock(all_tables)))
508
544
  {
509
545
    if (lex->describe)
588
624
 
589
625
 
590
626
void
591
 
mysql_init_select(LEX *lex)
 
627
init_select(LEX *lex)
592
628
{
593
629
  Select_Lex *select_lex= lex->current_select;
594
630
  select_lex->init_select();
602
638
 
603
639
 
604
640
bool
605
 
mysql_new_select(LEX *lex, bool move_down)
 
641
new_select(LEX *lex, bool move_down)
606
642
{
607
643
  Select_Lex *select_lex;
608
644
  Session *session= lex->session;
609
645
 
610
646
  if (!(select_lex= new (session->mem_root) Select_Lex()))
611
 
    return(1);
 
647
    return true;
 
648
 
612
649
  select_lex->select_number= ++session->select_number;
613
650
  select_lex->parent_lex= lex; /* Used in init_query. */
614
651
  select_lex->init_query();
615
652
  select_lex->init_select();
616
653
  lex->nest_level++;
 
654
 
617
655
  if (lex->nest_level > (int) MAX_SELECT_NESTING)
618
656
  {
619
657
    my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,MYF(0),MAX_SELECT_NESTING);
620
658
    return(1);
621
659
  }
 
660
 
622
661
  select_lex->nest_level= lex->nest_level;
623
662
  if (move_down)
624
663
  {
646
685
    if (lex->current_select->order_list.first && !lex->current_select->braces)
647
686
    {
648
687
      my_error(ER_WRONG_USAGE, MYF(0), "UNION", "order_st BY");
649
 
      return(1);
 
688
      return true;
650
689
    }
 
690
 
651
691
    select_lex->include_neighbour(lex->current_select);
652
692
    Select_Lex_Unit *unit= select_lex->master_unit();
653
 
    if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->session))
654
 
      return(1);
 
693
 
 
694
    if (not unit->fake_select_lex && unit->add_fake_select_lex(lex->session))
 
695
      return true;
 
696
 
655
697
    select_lex->context.outer_context=
656
698
                unit->first_select()->context.outer_context;
657
699
  }
664
706
    list
665
707
  */
666
708
  select_lex->context.resolve_in_select_list= true;
667
 
  return(0);
 
709
 
 
710
  return false;
668
711
}
669
712
 
670
713
/**
677
720
  @param var_name               Variable name
678
721
*/
679
722
 
680
 
void create_select_for_variable(const char *var_name)
 
723
void create_select_for_variable(Session *session, const char *var_name)
681
724
{
682
 
  Session *session;
683
725
  LEX *lex;
684
726
  LEX_STRING tmp, null_lex_string;
685
727
  Item *var;
686
728
  char buff[MAX_SYS_VAR_LENGTH*2+4+8];
687
729
  char *end= buff;
688
730
 
689
 
  session= current_session;
690
731
  lex= session->lex;
691
 
  mysql_init_select(lex);
 
732
  init_select(lex);
692
733
  lex->sql_command= SQLCOM_SELECT;
693
734
  tmp.str= (char*) var_name;
694
735
  tmp.length=strlen(var_name);
703
744
    var->set_name(buff, end-buff, system_charset_info);
704
745
    session->add_item_to_list(var);
705
746
  }
706
 
  return;
707
747
}
708
748
 
709
749
 
715
755
  @param       length  Length of the query text
716
756
*/
717
757
 
718
 
void mysql_parse(Session *session, const char *inBuf, uint32_t length)
 
758
void parse(Session *session, const char *inBuf, uint32_t length)
719
759
{
720
 
  boost::posix_time::ptime start_time=boost::posix_time::microsec_clock::local_time();
721
760
  session->lex->start(session);
722
761
 
723
762
  session->reset_for_next_command();
744
783
      {
745
784
        DRIZZLE_QUERY_EXEC_START(session->getQueryString()->c_str(),
746
785
                                 session->thread_id,
747
 
                                 const_cast<const char *>(session->db.empty() ? "" : session->db.c_str()));
 
786
                                 const_cast<const char *>(session->schema()->c_str()));
748
787
        // Implement Views here --Brian
749
788
        /* Actually execute the query */
750
789
        try 
751
790
        {
752
 
          mysql_execute_command(session);
 
791
          execute_command(session);
753
792
        }
754
793
        catch (...)
755
794
        {
756
795
          // Just try to catch any random failures that could have come
757
796
          // during execution.
 
797
          DRIZZLE_ABORT;
758
798
        }
759
799
        DRIZZLE_QUERY_EXEC_DONE(0);
760
800
      }
768
808
  session->set_proc_info("freeing items");
769
809
  session->end_statement();
770
810
  session->cleanup_after_query();
771
 
  boost::posix_time::ptime end_time=boost::posix_time::microsec_clock::local_time();
772
 
  session->status_var.execution_time_nsec+=(end_time-start_time).total_microseconds();
 
811
  session->set_end_timer();
773
812
}
774
813
 
775
814
 
829
868
    */
830
869
    if (default_value->type() == Item::FUNC_ITEM &&
831
870
        !(((Item_func*)default_value)->functype() == Item_func::NOW_FUNC &&
832
 
         type == DRIZZLE_TYPE_TIMESTAMP))
 
871
         (type == DRIZZLE_TYPE_TIMESTAMP or type == DRIZZLE_TYPE_MICROTIME)))
833
872
    {
834
873
      my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
835
874
      return true;
837
876
    else if (default_value->type() == Item::NULL_ITEM)
838
877
    {
839
878
      default_value= 0;
840
 
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
841
 
          NOT_NULL_FLAG)
 
879
      if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG)
842
880
      {
843
881
        my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
844
882
        return true;
851
889
    }
852
890
  }
853
891
 
854
 
  if (on_update_value && type != DRIZZLE_TYPE_TIMESTAMP)
 
892
  if (on_update_value && (type != DRIZZLE_TYPE_TIMESTAMP and type != DRIZZLE_TYPE_MICROTIME))
855
893
  {
856
894
    my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
857
895
    return true;
870
908
}
871
909
 
872
910
 
873
 
/** Store position for column in ALTER TABLE .. ADD column. */
874
 
 
875
 
void store_position_for_column(const char *name)
876
 
{
877
 
  current_session->lex->last_field->after=const_cast<char*> (name);
878
 
}
879
 
 
880
911
/**
881
912
  Add a table to list of used tables.
882
913
 
897
928
*/
898
929
 
899
930
TableList *Select_Lex::add_table_to_list(Session *session,
900
 
                                                             Table_ident *table,
901
 
                                                             LEX_STRING *alias,
902
 
                                                             const bitset<NUM_OF_TABLE_OPTIONS>& table_options,
903
 
                                                             thr_lock_type lock_type,
904
 
                                                             List<Index_hint> *index_hints_arg,
 
931
                                         Table_ident *table,
 
932
                                         LEX_STRING *alias,
 
933
                                         const bitset<NUM_OF_TABLE_OPTIONS>& table_options,
 
934
                                         thr_lock_type lock_type,
 
935
                                         List<Index_hint> *index_hints_arg,
905
936
                                         LEX_STRING *option)
906
937
{
907
938
  TableList *ptr;
923
954
  {
924
955
    my_casedn_str(files_charset_info, table->db.str);
925
956
 
926
 
    SchemaIdentifier schema_identifier(string(table->db.str));
 
957
    identifier::Schema schema_identifier(string(table->db.str));
927
958
    if (not check_db_name(session, schema_identifier))
928
959
    {
929
960
 
940
971
                 ER(ER_DERIVED_MUST_HAVE_ALIAS), MYF(0));
941
972
      return NULL;
942
973
    }
943
 
    if (!(alias_str= (char*) session->memdup(alias_str,table->table.length+1)))
 
974
    if (!(alias_str= (char*) session->getMemRoot()->duplicate(alias_str,table->table.length+1)))
944
975
      return NULL;
945
976
  }
946
977
  if (!(ptr = (TableList *) session->calloc(sizeof(TableList))))
976
1007
         tables ;
977
1008
         tables=tables->next_local)
978
1009
    {
979
 
      if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
980
 
          !strcasecmp(ptr->getSchemaName(), tables->getSchemaName()))
 
1010
      if (not my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
 
1011
          not my_strcasecmp(system_charset_info, ptr->getSchemaName(), tables->getSchemaName()))
981
1012
      {
982
1013
        my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str);
983
1014
        return NULL;
1041
1072
bool Select_Lex::init_nested_join(Session *session)
1042
1073
{
1043
1074
  TableList *ptr;
1044
 
  nested_join_st *nested_join;
 
1075
  NestedJoin *nested_join;
1045
1076
 
1046
1077
  if (!(ptr= (TableList*) session->calloc(ALIGN_SIZE(sizeof(TableList))+
1047
 
                                       sizeof(nested_join_st))))
 
1078
                                       sizeof(NestedJoin))))
1048
1079
    return true;
1049
 
  ptr->setNestedJoin(((nested_join_st*) ((unsigned char*) ptr + ALIGN_SIZE(sizeof(TableList)))));
 
1080
  ptr->setNestedJoin(((NestedJoin*) ((unsigned char*) ptr + ALIGN_SIZE(sizeof(TableList)))));
1050
1081
  nested_join= ptr->getNestedJoin();
1051
1082
  join_list->push_front(ptr);
1052
1083
  ptr->setEmbedding(embedding);
1076
1107
TableList *Select_Lex::end_nested_join(Session *)
1077
1108
{
1078
1109
  TableList *ptr;
1079
 
  nested_join_st *nested_join;
 
1110
  NestedJoin *nested_join;
1080
1111
 
1081
1112
  assert(embedding);
1082
1113
  ptr= embedding;
1117
1148
TableList *Select_Lex::nest_last_join(Session *session)
1118
1149
{
1119
1150
  TableList *ptr;
1120
 
  nested_join_st *nested_join;
 
1151
  NestedJoin *nested_join;
1121
1152
  List<TableList> *embedded_list;
1122
1153
 
1123
1154
  if (!(ptr= (TableList*) session->calloc(ALIGN_SIZE(sizeof(TableList))+
1124
 
                                          sizeof(nested_join_st))))
 
1155
                                          sizeof(NestedJoin))))
1125
1156
    return NULL;
1126
 
  ptr->setNestedJoin(((nested_join_st*) ((unsigned char*) ptr + ALIGN_SIZE(sizeof(TableList)))));
 
1157
  ptr->setNestedJoin(((NestedJoin*) ((unsigned char*) ptr + ALIGN_SIZE(sizeof(TableList)))));
1127
1158
  nested_join= ptr->getNestedJoin();
1128
1159
  ptr->setEmbedding(embedding);
1129
1160
  ptr->setJoinList(join_list);
1415
1446
 
1416
1447
 
1417
1448
/**
1418
 
  kill on thread.
1419
 
 
1420
 
  @param session                        Thread class
1421
 
  @param id                     Thread id
1422
 
  @param only_kill_query        Should it kill the query or the connection
1423
 
 
1424
 
  @note
1425
 
    This is written such that we have a short lock on LOCK_thread_count
1426
 
*/
1427
 
 
1428
 
static unsigned int kill_one_thread(session_id_t id, bool only_kill_query)
1429
 
{
1430
 
  uint32_t error= ER_NO_SUCH_THREAD;
1431
 
  
1432
 
  Session::shared_ptr session= session::Cache::singleton().find(id);
1433
 
 
1434
 
  if (not session)
1435
 
    return error;
1436
 
 
1437
 
  if (session->isViewable())
1438
 
  {
1439
 
    session->awake(only_kill_query ? Session::KILL_QUERY : Session::KILL_CONNECTION);
1440
 
    error= 0;
1441
 
  }
1442
 
 
1443
 
  return error;
1444
 
}
1445
 
 
1446
 
 
1447
 
/*
1448
 
  kills a thread and sends response
1449
 
 
1450
 
  SYNOPSIS
1451
 
    sql_kill()
1452
 
    session                     Thread class
1453
 
    id                  Thread id
1454
 
    only_kill_query     Should it kill the query or the connection
1455
 
*/
1456
 
 
1457
 
void sql_kill(Session *session, int64_t id, bool only_kill_query)
1458
 
{
1459
 
  uint32_t error;
1460
 
 
1461
 
  if (not (error= kill_one_thread(id, only_kill_query)))
1462
 
    session->my_ok();
1463
 
  else
1464
 
    my_error(error, MYF(0), id);
1465
 
}
1466
 
 
1467
 
 
1468
 
/**
1469
1449
  Check if the select is a simple select (not an union).
1470
1450
 
1471
1451
  @retval
1474
1454
    1   error   ; In this case the error messege is sent to the client
1475
1455
*/
1476
1456
 
1477
 
bool check_simple_select()
 
1457
bool check_simple_select(Session::pointer session)
1478
1458
{
1479
 
  Session *session= current_session;
1480
1459
  LEX *lex= session->lex;
1481
1460
  if (lex->current_select != &lex->select_lex)
1482
1461
  {
1593
1572
 
1594
1573
 
1595
1574
/**
1596
 
  CREATE TABLE query pre-check.
1597
 
 
1598
 
  @param session                        Thread handler
1599
 
  @param tables         Global table list
1600
 
  @param create_table           Table which will be created
1601
 
 
1602
 
  @retval
1603
 
    false   OK
1604
 
  @retval
1605
 
    true   Error
1606
 
*/
1607
 
 
1608
 
bool create_table_precheck(TableIdentifier &identifier)
1609
 
{
1610
 
  if (not plugin::StorageEngine::canCreateTable(identifier))
1611
 
  {
1612
 
    my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", identifier.getSchemaName().c_str());
1613
 
    return true;
1614
 
  }
1615
 
 
1616
 
  if (not plugin::StorageEngine::doesSchemaExist(identifier))
1617
 
  {
1618
 
    my_error(ER_BAD_DB_ERROR, MYF(0), identifier.getSchemaName().c_str());
1619
 
    return true;
1620
 
  }
1621
 
 
1622
 
  return false;
1623
 
}
1624
 
 
1625
 
 
1626
 
/**
1627
1575
  negate given expression.
1628
1576
 
1629
1577
  @param session  thread handler
1690
1638
}
1691
1639
 
1692
1640
 
1693
 
bool check_identifier_name(LEX_STRING *str, uint32_t err_code,
 
1641
bool check_identifier_name(LEX_STRING *str, error_t err_code,
1694
1642
                           uint32_t max_char_length,
1695
1643
                           const char *param_for_err_msg)
1696
1644
{
1716
1664
 
1717
1665
  switch (err_code)
1718
1666
  {
1719
 
  case 0:
 
1667
  case EE_OK:
1720
1668
    break;
1721
1669
  case ER_WRONG_STRING_LENGTH:
1722
1670
    my_error(err_code, MYF(0), str->str, param_for_err_msg, max_char_length);
1728
1676
    assert(0);
1729
1677
    break;
1730
1678
  }
 
1679
 
1731
1680
  return true;
1732
1681
}
1733
1682
 
1756
1705
 
1757
1706
  /* Parse the query. */
1758
1707
 
1759
 
  bool mysql_parse_status= DRIZZLEparse(session) != 0;
 
1708
  bool parse_status= DRIZZLEparse(session) != 0;
1760
1709
 
1761
1710
  /* Check that if DRIZZLEparse() failed, session->is_error() is set. */
1762
1711
 
1763
 
  assert(!mysql_parse_status || session->is_error());
 
1712
  assert(!parse_status || session->is_error());
1764
1713
 
1765
1714
  /* Reset Lex_input_stream. */
1766
1715
 
1767
1716
  session->m_lip= NULL;
1768
1717
 
1769
 
  DRIZZLE_QUERY_PARSE_DONE(mysql_parse_status || session->is_fatal_error);
 
1718
  DRIZZLE_QUERY_PARSE_DONE(parse_status || session->is_fatal_error);
1770
1719
 
1771
1720
  /* That's it. */
1772
1721
 
1773
 
  return mysql_parse_status || session->is_fatal_error;
 
1722
  return parse_status || session->is_fatal_error;
1774
1723
}
1775
1724
 
1776
1725
/**