~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_load.cc

Removed load xml infile. Hope nobody liked it. Now the only thing we need xml.c
for anymore is charsets... so when _those_ go away... BWAHAHAHA

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
 
16
16
 
17
17
/* Copy data from a textfile to table */
18
 
/* 2006-12 Erik Wetterberg : LOAD XML added */
19
18
 
20
19
#include <drizzled/server_includes.h>
21
20
#include "sql_repl.h"
22
21
#include <drizzled/drizzled_error_messages.h>
23
22
 
24
 
class XML_TAG {
25
 
public:
26
 
  int level;
27
 
  String field;
28
 
  String value;
29
 
  XML_TAG(int l, String f, String v);
30
 
};
31
 
 
32
 
 
33
 
XML_TAG::XML_TAG(int l, String f, String v)
34
 
{
35
 
  level= l;
36
 
  field.append(f);
37
 
  value.append(v);
38
 
}
39
 
 
40
23
 
41
24
class READ_INFO {
42
25
  File  file;
52
35
  bool  need_end_io_cache;
53
36
  IO_CACHE cache;
54
37
  NET *io_net;
55
 
  int level; /* for load xml */
56
38
 
57
39
public:
58
40
  bool error,line_cuted,found_null,enclosed;
70
52
  char unescape(char chr);
71
53
  int terminator(char *ptr,uint length);
72
54
  bool find_start_of_fields();
73
 
  /* load xml */
74
 
  List<XML_TAG> taglist;
75
 
  int read_value(int delim, String *val);
76
 
  int read_xml();
77
 
  int clear_level(int level);
78
55
 
79
56
  /*
80
57
    We need to force cache close before destructor is invoked to log
105
82
                          String &enclosed, ulong skip_lines,
106
83
                          bool ignore_check_option_errors);
107
84
 
108
 
static int read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
109
 
                          List<Item> &fields_vars, List<Item> &set_fields,
110
 
                          List<Item> &set_values, READ_INFO &read_info,
111
 
                          String &enclosed, ulong skip_lines,
112
 
                          bool ignore_check_option_errors);
113
 
 
114
85
static bool write_execute_load_query_log_event(THD *thd,
115
86
                                               bool duplicates, bool ignore,
116
87
                                               bool transactional_table,
355
326
  thd->count_cuted_fields= CHECK_FIELD_WARN;            /* calc cuted fields */
356
327
  thd->cuted_fields=0L;
357
328
  /* Skip lines if there is a line terminator */
358
 
  if (ex->line_term->length() && ex->filetype != FILETYPE_XML)
 
329
  if (ex->line_term->length())
359
330
  {
360
331
    /* ex->skip_lines needs to be preserved for logging */
361
332
    while (skip_lines > 0)
383
354
                             (MODE_STRICT_TRANS_TABLES |
384
355
                              MODE_STRICT_ALL_TABLES)));
385
356
 
386
 
    if (ex->filetype == FILETYPE_XML) /* load xml */
387
 
      error= read_xml_field(thd, info, table_list, fields_vars,
388
 
                            set_fields, set_values, read_info,
389
 
                            *(ex->line_term), skip_lines, ignore);
390
 
    else if (!field_term->length() && !enclosed->length())
 
357
    if (!field_term->length() && !enclosed->length())
391
358
      error= read_fixed_length(thd, info, table_list, fields_vars,
392
359
                               set_fields, set_values, read_info,
393
360
                               skip_lines, ignore);
831
798
}
832
799
 
833
800
 
834
 
/****************************************************************************
835
 
** Read rows in xml format
836
 
****************************************************************************/
837
 
static int
838
 
read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
839
 
               List<Item> &fields_vars, List<Item> &set_fields,
840
 
               List<Item> &set_values, READ_INFO &read_info,
841
 
               String &row_tag __attribute__((unused)),
842
 
               ulong skip_lines,
843
 
               bool ignore_check_option_errors)
844
 
{
845
 
  List_iterator_fast<Item> it(fields_vars);
846
 
  Item *item;
847
 
  TABLE *table= table_list->table;
848
 
  bool no_trans_update_stmt;
849
 
  const CHARSET_INFO * const cs= read_info.read_charset;
850
 
 
851
 
  no_trans_update_stmt= !table->file->has_transactions();
852
 
 
853
 
  for ( ; ; it.rewind())
854
 
  {
855
 
    if (thd->killed)
856
 
    {
857
 
      thd->send_kill_message();
858
 
      return(1);
859
 
    }
860
 
    
861
 
    // read row tag and save values into tag list
862
 
    if (read_info.read_xml())
863
 
      break;
864
 
    
865
 
    List_iterator_fast<XML_TAG> xmlit(read_info.taglist);
866
 
    xmlit.rewind();
867
 
    XML_TAG *tag= NULL;
868
 
    
869
 
    
870
 
    restore_record(table, s->default_values);
871
 
    
872
 
    while ((item= it++))
873
 
    {
874
 
      /* If this line is to be skipped we don't want to fill field or var */
875
 
      if (skip_lines)
876
 
        continue;
877
 
      
878
 
      /* find field in tag list */
879
 
      xmlit.rewind();
880
 
      tag= xmlit++;
881
 
      
882
 
      while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
883
 
        tag= xmlit++;
884
 
      
885
 
      if (!tag) // found null
886
 
      {
887
 
        if (item->type() == Item::FIELD_ITEM)
888
 
        {
889
 
          Field *field= ((Item_field *) item)->field;
890
 
          field->reset();
891
 
          field->set_null();
892
 
          if (field == table->next_number_field)
893
 
            table->auto_increment_field_not_null= true;
894
 
          if (!field->maybe_null())
895
 
          {
896
 
            if (field->type() == DRIZZLE_TYPE_TIMESTAMP)
897
 
              ((Field_timestamp *) field)->set_time();
898
 
            else if (field != table->next_number_field)
899
 
              field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
900
 
                                 ER_WARN_NULL_TO_NOTNULL, 1);
901
 
          }
902
 
        }
903
 
        else
904
 
          ((Item_user_var_as_out_param *) item)->set_null_value(cs);
905
 
        continue;
906
 
      }
907
 
 
908
 
      if (item->type() == Item::FIELD_ITEM)
909
 
      {
910
 
 
911
 
        Field *field= ((Item_field *)item)->field;
912
 
        field->set_notnull();
913
 
        if (field == table->next_number_field)
914
 
          table->auto_increment_field_not_null= true;
915
 
        field->store((char *) tag->value.ptr(), tag->value.length(), cs);
916
 
      }
917
 
      else
918
 
        ((Item_user_var_as_out_param *) item)->set_value(
919
 
                                                 (char *) tag->value.ptr(), 
920
 
                                                 tag->value.length(), cs);
921
 
    }
922
 
    
923
 
    if (read_info.error)
924
 
      break;
925
 
    
926
 
    if (skip_lines)
927
 
    {
928
 
      skip_lines--;
929
 
      continue;
930
 
    }
931
 
    
932
 
    if (item)
933
 
    {
934
 
      /* Have not read any field, thus input file is simply ended */
935
 
      if (item == fields_vars.head())
936
 
        break;
937
 
      
938
 
      for ( ; item; item= it++)
939
 
      {
940
 
        if (item->type() == Item::FIELD_ITEM)
941
 
        {
942
 
          /*
943
 
            QQ: We probably should not throw warning for each field.
944
 
            But how about intention to always have the same number
945
 
            of warnings in THD::cuted_fields (and get rid of cuted_fields
946
 
            in the end ?)
947
 
          */
948
 
          thd->cuted_fields++;
949
 
          push_warning_printf(thd, DRIZZLE_ERROR::WARN_LEVEL_WARN,
950
 
                              ER_WARN_TOO_FEW_RECORDS,
951
 
                              ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count);
952
 
        }
953
 
        else
954
 
          ((Item_user_var_as_out_param *)item)->set_null_value(cs);
955
 
      }
956
 
    }
957
 
 
958
 
    if (thd->killed || fill_record(thd, set_fields, set_values,
959
 
                    ignore_check_option_errors))
960
 
      return(1);
961
 
 
962
 
    if (write_record(thd, table, &info))
963
 
      return(1);
964
 
    
965
 
    /*
966
 
      We don't need to reset auto-increment field since we are restoring
967
 
      its default value at the beginning of each loop iteration.
968
 
    */
969
 
    thd->transaction.stmt.modified_non_trans_table= no_trans_update_stmt;
970
 
    thd->row_count++;
971
 
  }
972
 
  return(test(read_info.error));
973
 
} /* load xml end */
974
 
 
975
 
 
976
801
/* Unescape all escape characters, mark \N as null */
977
802
 
978
803
char
1011
836
  field_term_length= field_term.length();
1012
837
  line_term_ptr=(char*) line_term.ptr();
1013
838
  line_term_length= line_term.length();
1014
 
  level= 0; /* for load xml */
1015
839
  if (line_start.length() == 0)
1016
840
  {
1017
841
    line_start_ptr=0;
1085
909
    my_free((uchar*) buffer,MYF(0));
1086
910
    error=1;
1087
911
  }
1088
 
  List_iterator<XML_TAG> xmlit(taglist);
1089
 
  XML_TAG *t;
1090
 
  while ((t= xmlit++))
1091
 
    delete(t);
1092
912
}
1093
913
 
1094
914
 
1422
1242
}
1423
1243
 
1424
1244
 
1425
 
/*
1426
 
  Clear taglist from tags with a specified level
1427
 
*/
1428
 
int READ_INFO::clear_level(int level)
1429
 
{
1430
 
  List_iterator<XML_TAG> xmlit(taglist);
1431
 
  xmlit.rewind();
1432
 
  XML_TAG *tag;
1433
 
  
1434
 
  while ((tag= xmlit++))
1435
 
  {
1436
 
     if(tag->level >= level)
1437
 
     {
1438
 
       xmlit.remove();
1439
 
       delete tag;
1440
 
     }
1441
 
  }
1442
 
  return(0);
1443
 
}
1444
 
 
1445
 
 
1446
 
/*
1447
 
  Convert an XML entity to Unicode value.
1448
 
  Return -1 on error;
1449
 
*/
1450
 
static int
1451
 
my_xml_entity_to_char(const char *name, uint length)
1452
 
{
1453
 
  if (length == 2)
1454
 
  {
1455
 
    if (!memcmp(name, "gt", length))
1456
 
      return '>';
1457
 
    if (!memcmp(name, "lt", length))
1458
 
      return '<';
1459
 
  }
1460
 
  else if (length == 3)
1461
 
  {
1462
 
    if (!memcmp(name, "amp", length))
1463
 
      return '&';
1464
 
  }
1465
 
  else if (length == 4)
1466
 
  {
1467
 
    if (!memcmp(name, "quot", length))
1468
 
      return '"';
1469
 
    if (!memcmp(name, "apos", length))
1470
 
      return '\'';
1471
 
  }
1472
 
  return -1;
1473
 
}
1474
 
 
1475
 
 
1476
 
/**
1477
 
  @brief Convert newline, linefeed, tab to space
1478
 
  
1479
 
  @param chr    character
1480
 
  
1481
 
  @details According to the "XML 1.0" standard,
1482
 
           only space (#x20) characters, carriage returns,
1483
 
           line feeds or tabs are considered as spaces.
1484
 
           Convert all of them to space (#x20) for parsing simplicity.
1485
 
*/
1486
 
static int
1487
 
my_tospace(int chr)
1488
 
{
1489
 
  return (chr == '\t' || chr == '\r' || chr == '\n') ? ' ' : chr;
1490
 
}
1491
 
 
1492
 
 
1493
 
/*
1494
 
  Read an xml value: handle multibyte and xml escape
1495
 
*/
1496
 
int READ_INFO::read_value(int delim, String *val)
1497
 
{
1498
 
  int chr;
1499
 
  String tmp;
1500
 
 
1501
 
  for (chr= my_tospace(GET); chr != delim && chr != my_b_EOF; )
1502
 
  {
1503
 
#ifdef USE_MB
1504
 
    if (my_mbcharlen(read_charset, chr) > 1)
1505
 
    {
1506
 
      int i, ml= my_mbcharlen(read_charset, chr);
1507
 
      for (i= 1; i < ml; i++) 
1508
 
      {
1509
 
        val->append(chr);
1510
 
        /*
1511
 
          Don't use my_tospace() in the middle of a multi-byte character
1512
 
          TODO: check that the multi-byte sequence is valid.
1513
 
        */
1514
 
        chr= GET; 
1515
 
        if (chr == my_b_EOF)
1516
 
          return chr;
1517
 
      }
1518
 
    }
1519
 
#endif
1520
 
    if(chr == '&')
1521
 
    {
1522
 
      tmp.length(0);
1523
 
      for (chr= my_tospace(GET) ; chr != ';' ; chr= my_tospace(GET))
1524
 
      {
1525
 
        if (chr == my_b_EOF)
1526
 
          return chr;
1527
 
        tmp.append(chr);
1528
 
      }
1529
 
      if ((chr= my_xml_entity_to_char(tmp.ptr(), tmp.length())) >= 0)
1530
 
        val->append(chr);
1531
 
      else
1532
 
      {
1533
 
        val->append('&');
1534
 
        val->append(tmp);
1535
 
        val->append(';'); 
1536
 
      }
1537
 
    }
1538
 
    else
1539
 
      val->append(chr);
1540
 
    chr= my_tospace(GET);
1541
 
  }            
1542
 
  return chr;
1543
 
}
1544
 
 
1545
 
 
1546
 
/*
1547
 
  Read a record in xml format
1548
 
  tags and attributes are stored in taglist
1549
 
  when tag set in ROWS IDENTIFIED BY is closed, we are ready and return
1550
 
*/
1551
 
int READ_INFO::read_xml()
1552
 
{
1553
 
  int chr, chr2, chr3;
1554
 
  int delim= 0;
1555
 
  String tag, attribute, value;
1556
 
  bool in_tag= false;
1557
 
  
1558
 
  tag.length(0);
1559
 
  attribute.length(0);
1560
 
  value.length(0);
1561
 
  
1562
 
  for (chr= my_tospace(GET); chr != my_b_EOF ; )
1563
 
  {
1564
 
    switch(chr){
1565
 
    case '<':  /* read tag */
1566
 
        /* TODO: check if this is a comment <!-- comment -->  */
1567
 
      chr= my_tospace(GET);
1568
 
      if(chr == '!')
1569
 
      {
1570
 
        chr2= GET;
1571
 
        chr3= GET;
1572
 
        
1573
 
        if(chr2 == '-' && chr3 == '-')
1574
 
        {
1575
 
          chr2= 0;
1576
 
          chr3= 0;
1577
 
          chr= my_tospace(GET);
1578
 
          
1579
 
          while(chr != '>' || chr2 != '-' || chr3 != '-')
1580
 
          {
1581
 
            if(chr == '-')
1582
 
            {
1583
 
              chr3= chr2;
1584
 
              chr2= chr;
1585
 
            }
1586
 
            else if (chr2 == '-')
1587
 
            {
1588
 
              chr2= 0;
1589
 
              chr3= 0;
1590
 
            }
1591
 
            chr= my_tospace(GET);
1592
 
            if (chr == my_b_EOF)
1593
 
              goto found_eof;
1594
 
          }
1595
 
          break;
1596
 
        }
1597
 
      }
1598
 
      
1599
 
      tag.length(0);
1600
 
      while(chr != '>' && chr != ' ' && chr != '/' && chr != my_b_EOF)
1601
 
      {
1602
 
        if(chr != delim) /* fix for the '<field name =' format */
1603
 
          tag.append(chr);
1604
 
        chr= my_tospace(GET);
1605
 
      }
1606
 
      
1607
 
      if(chr == ' ' || chr == '>')
1608
 
      {
1609
 
        level++;
1610
 
        clear_level(level + 1);
1611
 
      }
1612
 
      
1613
 
      if (chr == ' ')
1614
 
        in_tag= true;
1615
 
      else 
1616
 
        in_tag= false;
1617
 
      break;
1618
 
      
1619
 
    case ' ': /* read attribute */
1620
 
      while(chr == ' ')  /* skip blanks */
1621
 
        chr= my_tospace(GET);
1622
 
      
1623
 
      if(!in_tag)
1624
 
        break;
1625
 
      
1626
 
      while(chr != '=' && chr != '/' && chr != '>' && chr != my_b_EOF)
1627
 
      {
1628
 
        attribute.append(chr);
1629
 
        chr= my_tospace(GET);
1630
 
      }
1631
 
      break;
1632
 
      
1633
 
    case '>': /* end tag - read tag value */
1634
 
      in_tag= false;
1635
 
      chr= read_value('<', &value);
1636
 
      if(chr == my_b_EOF)
1637
 
        goto found_eof;
1638
 
      
1639
 
      /* save value to list */
1640
 
      if(tag.length() > 0 && value.length() > 0)
1641
 
        taglist.push_front( new XML_TAG(level, tag, value));
1642
 
 
1643
 
      tag.length(0);
1644
 
      value.length(0);
1645
 
      attribute.length(0);
1646
 
      break;
1647
 
      
1648
 
    case '/': /* close tag */
1649
 
      level--;
1650
 
      chr= my_tospace(GET);
1651
 
      if(chr != '>')   /* if this is an empty tag <tag   /> */
1652
 
        tag.length(0); /* we should keep tag value          */
1653
 
      while(chr != '>' && chr != my_b_EOF)
1654
 
      {
1655
 
        tag.append(chr);
1656
 
        chr= my_tospace(GET);
1657
 
      }
1658
 
      
1659
 
      if((tag.length() == line_term_length -2) &&
1660
 
         (strncmp(tag.c_ptr_safe(), line_term_ptr + 1, tag.length()) == 0))
1661
 
         return(0); //normal return
1662
 
 
1663
 
      chr= my_tospace(GET);
1664
 
      break;   
1665
 
      
1666
 
    case '=': /* attribute name end - read the value */
1667
 
      //check for tag field and attribute name
1668
 
      if(!memcmp(tag.c_ptr_safe(), STRING_WITH_LEN("field")) &&
1669
 
         !memcmp(attribute.c_ptr_safe(), STRING_WITH_LEN("name")))
1670
 
      {
1671
 
        /*
1672
 
          this is format <field name="xx">xx</field>
1673
 
          where actual fieldname is in attribute
1674
 
        */
1675
 
        delim= my_tospace(GET);
1676
 
        tag.length(0);
1677
 
        attribute.length(0);
1678
 
        chr= '<'; /* we pretend that it is a tag */
1679
 
        level--;
1680
 
        break;
1681
 
      }
1682
 
      
1683
 
      //check for " or '
1684
 
      chr= GET;
1685
 
      if (chr == my_b_EOF)
1686
 
        goto found_eof;
1687
 
      if(chr == '"' || chr == '\'')
1688
 
      {
1689
 
        delim= chr;
1690
 
      }
1691
 
      else
1692
 
      {
1693
 
        delim= ' '; /* no delimiter, use space */
1694
 
        PUSH(chr);
1695
 
      }
1696
 
      
1697
 
      chr= read_value(delim, &value);
1698
 
      if(attribute.length() > 0 && value.length() > 0)
1699
 
        taglist.push_front(new XML_TAG(level + 1, attribute, value));
1700
 
 
1701
 
      attribute.length(0);
1702
 
      value.length(0);
1703
 
      if (chr != ' ')
1704
 
        chr= my_tospace(GET);
1705
 
      break;
1706
 
    
1707
 
    default:
1708
 
      chr= my_tospace(GET);
1709
 
    } /* end switch */
1710
 
  } /* end while */
1711
 
  
1712
 
found_eof:
1713
 
  eof= 1;
1714
 
  return(1);
1715
 
}