~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libmysql/libmysql.c

  • Committer: Brian Aker
  • Date: 2008-07-02 20:17:52 UTC
  • Revision ID: brian@tangent.org-20080702201752-5vb7lk1ut6y1bhsk
First pass on removing binary protocol from client library.

Show diffs side-by-side

added added

removed removed

Lines of Context:
156
156
    if (!mysql_unix_port)
157
157
    {
158
158
      char *env;
159
 
#ifdef __WIN__
160
 
      mysql_unix_port = (char*) MYSQL_NAMEDPIPE;
161
 
#else
162
159
      mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
163
 
#endif
164
160
      if ((env = getenv("MYSQL_UNIX_PORT")))
165
161
        mysql_unix_port = env;
166
162
    }
167
163
    mysql_debug(NullS);
168
 
#if defined(SIGPIPE) && !defined(__WIN__) && !defined(__NETWARE__)
 
164
#if defined(SIGPIPE)
169
165
    (void) signal(SIGPIPE, SIG_IGN);
170
166
#endif
171
 
#ifdef EMBEDDED_LIBRARY
172
 
    if (argc > -1)
173
 
       result= init_embedded_server(argc, argv, groups);
174
 
#endif
175
167
  }
176
168
#ifdef THREAD
177
169
  else
198
190
  if (!mysql_client_init)
199
191
    return;
200
192
 
201
 
#ifdef EMBEDDED_LIBRARY
202
 
  end_embedded_server();
203
 
#endif
204
193
  finish_client_errs();
205
194
  vio_end();
206
195
 
1295
1284
  - mysql_stmt_fetch when there are no rows (always returns MYSQL_NO_DATA)
1296
1285
*/
1297
1286
 
1298
 
static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row);
1299
 
static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row);
1300
 
static int stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row);
1301
 
static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row);
1302
 
static int stmt_read_row_no_result_set(MYSQL_STMT *stmt, unsigned char **row);
1303
 
 
1304
1287
/*
1305
1288
  This function is used in mysql_stmt_store_result if
1306
1289
  STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
1307
1290
*/
1308
1291
static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data);
1309
 
static my_bool setup_one_fetch_function(MYSQL_BIND *, MYSQL_FIELD *field);
1310
1292
 
1311
1293
/* Auxilary function used to reset statement handle. */
1312
1294
 
1314
1296
#define RESET_LONG_DATA 2
1315
1297
#define RESET_STORE_RESULT 4
1316
1298
 
1317
 
static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags);
1318
 
 
1319
1299
/*
1320
1300
  Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
1321
1301
  values stored in network buffer.
1510
1490
  DBUG_RETURN(0);
1511
1491
}
1512
1492
 
1513
 
 
1514
 
/*
1515
 
  Allocate memory and init prepared statement structure.
1516
 
 
1517
 
  SYNOPSIS
1518
 
    mysql_stmt_init()
1519
 
    mysql   connection handle
1520
 
 
1521
 
  DESCRIPTION
1522
 
    This is an entry point of the new API. Returned handle stands for
1523
 
    a server-side prepared statement. Memory for this structure (~700
1524
 
    bytes) is allocated using 'malloc'. Once created, the handle can be
1525
 
    reused many times. Created statement handle is bound to connection
1526
 
    handle provided to this call: its lifetime is limited by lifetime
1527
 
    of connection.
1528
 
    'mysql_stmt_init()' is a pure local call, server side structure is
1529
 
    created only in mysql_stmt_prepare.
1530
 
    Next steps you may want to make:
1531
 
    - set a statement attribute (mysql_stmt_attr_set()),
1532
 
    - prepare statement handle with a query (mysql_stmt_prepare()),
1533
 
    - close statement handle and free its memory (mysql_stmt_close()),
1534
 
    - reset statement with mysql_stmt_reset() (a no-op which will
1535
 
      just return).
1536
 
    Behaviour of the rest of API calls on this statement is not defined yet
1537
 
    (though we're working on making each wrong call sequence return
1538
 
    error).
1539
 
 
1540
 
  RETURN VALUE
1541
 
    statement structure upon success and NULL if out of
1542
 
    memory
1543
 
*/
1544
 
 
1545
 
MYSQL_STMT * STDCALL
1546
 
mysql_stmt_init(MYSQL *mysql)
1547
 
{
1548
 
  MYSQL_STMT *stmt;
1549
 
  DBUG_ENTER("mysql_stmt_init");
1550
 
 
1551
 
  if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT),
1552
 
                                       MYF(MY_WME | MY_ZEROFILL))))
1553
 
  {
1554
 
    set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
1555
 
    DBUG_RETURN(0);
1556
 
  }
1557
 
 
1558
 
  init_alloc_root(&stmt->mem_root, 2048, 2048);
1559
 
  init_alloc_root(&stmt->result.alloc, 4096, 4096);
1560
 
  stmt->result.alloc.min_malloc= sizeof(MYSQL_ROWS);
1561
 
  mysql->stmts= list_add(mysql->stmts, &stmt->list);
1562
 
  stmt->list.data= stmt;
1563
 
  stmt->state= MYSQL_STMT_INIT_DONE;
1564
 
  stmt->mysql= mysql;
1565
 
  stmt->read_row_func= stmt_read_row_no_result_set;
1566
 
  stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS;
1567
 
  strmov(stmt->sqlstate, not_error_sqlstate);
1568
 
  /* The rest of statement members was bzeroed inside malloc */
1569
 
 
1570
 
  DBUG_RETURN(stmt);
1571
 
}
1572
 
 
1573
 
 
1574
 
/*
1575
 
  Prepare server side statement with query.
1576
 
 
1577
 
  SYNOPSIS
1578
 
    mysql_stmt_prepare()
1579
 
    stmt    statement handle
1580
 
    query   statement to prepare
1581
 
    length  statement length
1582
 
 
1583
 
  DESCRIPTION
1584
 
    Associate statement with statement handle. This is done both on
1585
 
    client and server sides. At this point the server parses given query
1586
 
    and creates an internal structure to represent it.
1587
 
    Next steps you may want to make:
1588
 
    - find out if this statement returns a result set by
1589
 
      calling mysql_stmt_field_count(), and get result set metadata
1590
 
      with mysql_stmt_result_metadata(),
1591
 
    - if query contains placeholders, bind input parameters to placeholders
1592
 
      using mysql_stmt_bind_param(),
1593
 
    - otherwise proceed directly to mysql_stmt_execute().
1594
 
 
1595
 
  IMPLEMENTATION NOTES
1596
 
  - if this is a re-prepare of the statement, first close previous data
1597
 
    structure on the server and free old statement data
1598
 
  - then send the query to server and get back number of placeholders,
1599
 
    number of columns in result set (if any), and result set metadata.
1600
 
    At the same time allocate memory for input and output parameters
1601
 
    to have less checks in mysql_stmt_bind_{param, result}.
1602
 
 
1603
 
  RETURN VALUES
1604
 
    0  success
1605
 
   !0  error
1606
 
*/
1607
 
 
1608
 
int STDCALL
1609
 
mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
1610
 
{
1611
 
  MYSQL *mysql= stmt->mysql;
1612
 
  DBUG_ENTER("mysql_stmt_prepare");
1613
 
 
1614
 
  if (!mysql)
1615
 
  {
1616
 
    /* mysql can be reset in mysql_close called from mysql_reconnect */
1617
 
    set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
1618
 
    DBUG_RETURN(1);
1619
 
  }
1620
 
 
1621
 
  /*
1622
 
    Reset the last error in any case: that would clear the statement
1623
 
    if the previous prepare failed.
1624
 
  */
1625
 
  stmt->last_errno= 0;
1626
 
  stmt->last_error[0]= '\0';
1627
 
 
1628
 
  if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
1629
 
  {
1630
 
    /* This is second prepare with another statement */
1631
 
    uchar buff[MYSQL_STMT_HEADER];               /* 4 bytes - stmt id */
1632
 
 
1633
 
    if (reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT))
1634
 
      DBUG_RETURN(1);
1635
 
    /*
1636
 
      These members must be reset for API to
1637
 
      function in case of error or misuse.
1638
 
    */
1639
 
    stmt->bind_param_done= stmt->bind_result_done= FALSE;
1640
 
    stmt->param_count= stmt->field_count= 0;
1641
 
    free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
1642
 
 
1643
 
    int4store(buff, stmt->stmt_id);
1644
 
 
1645
 
    /*
1646
 
      Close statement in server
1647
 
 
1648
 
      If there was a 'use' result from another statement, or from
1649
 
      mysql_use_result it won't be freed in mysql_stmt_free_result and
1650
 
      we should get 'Commands out of sync' here.
1651
 
    */
1652
 
    stmt->state= MYSQL_STMT_INIT_DONE;
1653
 
    if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))
1654
 
    {
1655
 
      set_stmt_errmsg(stmt, &mysql->net);
1656
 
      DBUG_RETURN(1);
1657
 
    }
1658
 
  }
1659
 
 
1660
 
  if (stmt_command(mysql, COM_STMT_PREPARE, (const uchar*) query, length, stmt))
1661
 
  {
1662
 
    set_stmt_errmsg(stmt, &mysql->net);
1663
 
    DBUG_RETURN(1);
1664
 
  }
1665
 
 
1666
 
  if ((*mysql->methods->read_prepare_result)(mysql, stmt))
1667
 
  {
1668
 
    set_stmt_errmsg(stmt, &mysql->net);
1669
 
    DBUG_RETURN(1);
1670
 
  }
1671
 
 
1672
 
  /*
1673
 
    alloc_root will return valid address even in case when param_count
1674
 
    and field_count are zero. Thus we should never rely on stmt->bind
1675
 
    or stmt->params when checking for existence of placeholders or
1676
 
    result set.
1677
 
  */
1678
 
  if (!(stmt->params= (MYSQL_BIND *) alloc_root(&stmt->mem_root,
1679
 
                                                sizeof(MYSQL_BIND)*
1680
 
                                                (stmt->param_count +
1681
 
                                                 stmt->field_count))))
1682
 
  {
1683
 
    set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
1684
 
    DBUG_RETURN(1);
1685
 
  }
1686
 
  stmt->bind= stmt->params + stmt->param_count;
1687
 
  stmt->state= MYSQL_STMT_PREPARE_DONE;
1688
 
  DBUG_PRINT("info", ("Parameter count: %u", stmt->param_count));
1689
 
  DBUG_RETURN(0);
1690
 
}
1691
 
 
1692
 
/*
1693
 
  Get result set metadata from reply to mysql_stmt_execute.
1694
 
  This is used mainly for SHOW commands, as metadata for these
1695
 
  commands is sent only with result set.
1696
 
  To be removed when all commands will fully support prepared mode.
1697
 
*/
1698
 
 
1699
 
static unsigned int alloc_stmt_fields(MYSQL_STMT *stmt)
1700
 
{
1701
 
  MYSQL_FIELD *fields, *field, *end;
1702
 
  MEM_ROOT *alloc= &stmt->mem_root;
1703
 
  MYSQL *mysql= stmt->mysql;
1704
 
 
1705
 
  stmt->field_count= mysql->field_count;
1706
 
 
1707
 
  /*
1708
 
    Get the field information for non-select statements
1709
 
    like SHOW and DESCRIBE commands
1710
 
  */
1711
 
  if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc,
1712
 
                                                 sizeof(MYSQL_FIELD) *
1713
 
                                                 stmt->field_count)) ||
1714
 
      !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc,
1715
 
                                              sizeof(MYSQL_BIND) *
1716
 
                                              stmt->field_count)))
1717
 
    return 0;
1718
 
 
1719
 
  for (fields= mysql->fields, end= fields+stmt->field_count,
1720
 
         field= stmt->fields;
1721
 
       field && fields < end; fields++, field++)
1722
 
  {
1723
 
    field->db       = strdup_root(alloc,fields->db);
1724
 
    field->table    = strdup_root(alloc,fields->table);
1725
 
    field->org_table= strdup_root(alloc,fields->org_table);
1726
 
    field->name     = strdup_root(alloc,fields->name);
1727
 
    field->org_name = strdup_root(alloc,fields->org_name);
1728
 
    field->charsetnr= fields->charsetnr;
1729
 
    field->length   = fields->length;
1730
 
    field->type     = fields->type;
1731
 
    field->flags    = fields->flags;
1732
 
    field->decimals = fields->decimals;
1733
 
    field->def      = fields->def ? strdup_root(alloc,fields->def): 0;
1734
 
    field->max_length= 0;
1735
 
  }
1736
 
  return stmt->field_count;
1737
 
}
1738
 
 
1739
 
 
1740
 
/*
1741
 
  Update result set columns metadata if it was sent again in
1742
 
  reply to COM_STMT_EXECUTE.
1743
 
*/
1744
 
 
1745
 
static void update_stmt_fields(MYSQL_STMT *stmt)
1746
 
{
1747
 
  MYSQL_FIELD *field= stmt->mysql->fields;
1748
 
  MYSQL_FIELD *field_end= field + stmt->field_count;
1749
 
  MYSQL_FIELD *stmt_field= stmt->fields;
1750
 
  MYSQL_BIND *my_bind= stmt->bind_result_done ? stmt->bind : 0;
1751
 
 
1752
 
  DBUG_ASSERT(stmt->field_count == stmt->mysql->field_count);
1753
 
 
1754
 
  for (; field < field_end; ++field, ++stmt_field)
1755
 
  {
1756
 
    stmt_field->charsetnr= field->charsetnr;
1757
 
    stmt_field->length   = field->length;
1758
 
    stmt_field->type     = field->type;
1759
 
    stmt_field->flags    = field->flags;
1760
 
    stmt_field->decimals = field->decimals;
1761
 
    if (my_bind)
1762
 
    {
1763
 
      /* Ignore return value: it should be 0 if bind_result succeeded. */
1764
 
      (void) setup_one_fetch_function(my_bind++, stmt_field);
1765
 
    }
1766
 
  }
1767
 
}
1768
 
 
1769
 
/*
1770
 
  Returns prepared statement metadata in the form of a result set.
1771
 
 
1772
 
  SYNOPSIS
1773
 
    mysql_stmt_result_metadata()
1774
 
    stmt  statement handle
1775
 
 
1776
 
  DESCRIPTION
1777
 
    This function should be used after mysql_stmt_execute().
1778
 
    You can safely check that prepared statement has a result set by calling
1779
 
    mysql_stmt_field_count(): if number of fields is not zero, you can call
1780
 
    this function to get fields metadata.
1781
 
    Next steps you may want to make:
1782
 
    - find out number of columns in result set by calling
1783
 
      mysql_num_fields(res) (the same value is returned by
1784
 
      mysql_stmt_field_count())
1785
 
    - fetch metadata for any column with mysql_fetch_field,
1786
 
      mysql_fetch_field_direct, mysql_fetch_fields, mysql_field_seek.
1787
 
    - free returned MYSQL_RES structure with mysql_free_result.
1788
 
    - proceed to binding of output parameters.
1789
 
 
1790
 
  RETURN
1791
 
    NULL  statement contains no result set or out of memory.
1792
 
          In the latter case you can retreive error message
1793
 
          with mysql_stmt_error.
1794
 
    MYSQL_RES  a result set with no rows
1795
 
*/
1796
 
 
1797
 
MYSQL_RES * STDCALL
1798
 
mysql_stmt_result_metadata(MYSQL_STMT *stmt)
1799
 
{
1800
 
  MYSQL_RES *result;
1801
 
  DBUG_ENTER("mysql_stmt_result_metadata");
1802
 
 
1803
 
  /*
1804
 
    stmt->fields is only defined if stmt->field_count is not null;
1805
 
    stmt->field_count is initialized in prepare.
1806
 
  */
1807
 
  if (!stmt->field_count)
1808
 
     DBUG_RETURN(0);
1809
 
 
1810
 
  if (!(result=(MYSQL_RES*) my_malloc(sizeof(*result),
1811
 
                                      MYF(MY_WME | MY_ZEROFILL))))
1812
 
  {
1813
 
    set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
1814
 
    DBUG_RETURN(0);
1815
 
  }
1816
 
 
1817
 
  result->methods=      stmt->mysql->methods;
1818
 
  result->eof=          1;                      /* Marker for buffered */
1819
 
  result->fields=       stmt->fields;
1820
 
  result->field_count=  stmt->field_count;
1821
 
  /* The rest of members of 'result' was bzeroed inside malloc */
1822
 
  DBUG_RETURN(result);
1823
 
}
1824
 
 
1825
 
 
1826
 
/*
1827
 
  Returns parameter columns meta information in the form of
1828
 
  result set.
1829
 
 
1830
 
  SYNOPSYS
1831
 
    mysql_stmt_param_metadata()
1832
 
    stmt    statement handle
1833
 
 
1834
 
  DESCRIPTION
1835
 
    This function can be called after you prepared the statement handle
1836
 
    with mysql_stmt_prepare().
1837
 
    XXX: not implemented yet.
1838
 
 
1839
 
  RETURN
1840
 
    MYSQL_RES on success, 0 if there is no metadata.
1841
 
    Currently this function always returns 0.
1842
 
*/
1843
 
 
1844
 
MYSQL_RES * STDCALL
1845
 
mysql_stmt_param_metadata(MYSQL_STMT *stmt)
1846
 
{
1847
 
  DBUG_ENTER("mysql_stmt_param_metadata");
1848
 
 
1849
 
  if (!stmt->param_count)
1850
 
    DBUG_RETURN(0);
1851
 
 
1852
 
  /*
1853
 
    TODO: Fix this when server sends the information.
1854
 
    Till then keep a dummy prototype.
1855
 
  */
1856
 
  DBUG_RETURN(0); 
1857
 
}
1858
 
 
1859
 
 
1860
 
/* Store type of parameter in network buffer. */
1861
 
 
1862
 
static void store_param_type(char **pos, MYSQL_BIND *param)
1863
 
{
1864
 
  uint typecode= param->buffer_type | (param->is_unsigned ? 32768 : 0);
1865
 
  int2store(*pos, typecode);
1866
 
  *pos+= 2;
1867
 
}
1868
 
 
1869
 
 
1870
 
/*
1871
 
  Functions to store parameter data in network packet.
1872
 
 
1873
 
  SYNOPSIS
1874
 
    store_param_xxx()
1875
 
    net                 MySQL NET connection
1876
 
    param               MySQL bind param
1877
 
 
1878
 
  DESCRIPTION
1879
 
    These funtions are invoked from mysql_stmt_execute() by
1880
 
    MYSQL_BIND::store_param_func pointer. This pointer is set once per
1881
 
    many executions in mysql_stmt_bind_param(). The caller must ensure
1882
 
    that network buffer have enough capacity to store parameter
1883
 
    (MYSQL_BIND::buffer_length contains needed number of bytes).
1884
 
*/
1885
 
 
1886
 
static void store_param_tinyint(NET *net, MYSQL_BIND *param)
1887
 
{
1888
 
  *(net->write_pos++)= *(uchar *) param->buffer;
1889
 
}
1890
 
 
1891
 
static void store_param_short(NET *net, MYSQL_BIND *param)
1892
 
{
1893
 
  short value= *(short*) param->buffer;
1894
 
  int2store(net->write_pos,value);
1895
 
  net->write_pos+=2;
1896
 
}
1897
 
 
1898
 
static void store_param_int32(NET *net, MYSQL_BIND *param)
1899
 
{
1900
 
  int32 value= *(int32*) param->buffer;
1901
 
  int4store(net->write_pos,value);
1902
 
  net->write_pos+=4;
1903
 
}
1904
 
 
1905
 
static void store_param_int64(NET *net, MYSQL_BIND *param)
1906
 
{
1907
 
  longlong value= *(longlong*) param->buffer;
1908
 
  int8store(net->write_pos,value);
1909
 
  net->write_pos+= 8;
1910
 
}
1911
 
 
1912
 
static void store_param_float(NET *net, MYSQL_BIND *param)
1913
 
{
1914
 
  float value= *(float*) param->buffer;
1915
 
  float4store(net->write_pos, value);
1916
 
  net->write_pos+= 4;
1917
 
}
1918
 
 
1919
 
static void store_param_double(NET *net, MYSQL_BIND *param)
1920
 
{
1921
 
  double value= *(double*) param->buffer;
1922
 
  float8store(net->write_pos, value);
1923
 
  net->write_pos+= 8;
1924
 
}
1925
 
 
1926
 
static void store_param_time(NET *net, MYSQL_BIND *param)
1927
 
{
1928
 
  MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
1929
 
  char buff[MAX_TIME_REP_LENGTH], *pos;
1930
 
  uint length;
1931
 
 
1932
 
  pos= buff+1;
1933
 
  pos[0]= tm->neg ? 1: 0;
1934
 
  int4store(pos+1, tm->day);
1935
 
  pos[5]= (uchar) tm->hour;
1936
 
  pos[6]= (uchar) tm->minute;
1937
 
  pos[7]= (uchar) tm->second;
1938
 
  int4store(pos+8, tm->second_part);
1939
 
  if (tm->second_part)
1940
 
    length= 12;
1941
 
  else if (tm->hour || tm->minute || tm->second || tm->day)
1942
 
    length= 8;
1943
 
  else
1944
 
    length= 0;
1945
 
  buff[0]= (char) length++;
1946
 
  memcpy((char *)net->write_pos, buff, length);
1947
 
  net->write_pos+= length;
1948
 
}
1949
 
 
1950
1493
static void net_store_datetime(NET *net, MYSQL_TIME *tm)
1951
1494
{
1952
1495
  char buff[MAX_DATETIME_REP_LENGTH], *pos;
1974
1517
  net->write_pos+= length;
1975
1518
}
1976
1519
 
1977
 
static void store_param_date(NET *net, MYSQL_BIND *param)
1978
 
{
1979
 
  MYSQL_TIME tm= *((MYSQL_TIME *) param->buffer);
1980
 
  tm.hour= tm.minute= tm.second= tm.second_part= 0;
1981
 
  net_store_datetime(net, &tm);
1982
 
}
1983
 
 
1984
 
static void store_param_datetime(NET *net, MYSQL_BIND *param)
1985
 
{
1986
 
  MYSQL_TIME *tm= (MYSQL_TIME *) param->buffer;
1987
 
  net_store_datetime(net, tm);
1988
 
}
1989
 
 
1990
 
static void store_param_str(NET *net, MYSQL_BIND *param)
1991
 
{
1992
 
  /* param->length is always set in mysql_stmt_bind_param */
1993
 
  ulong length= *param->length;
1994
 
  uchar *to= net_store_length(net->write_pos, length);
1995
 
  memcpy(to, param->buffer, length);
1996
 
  net->write_pos= to+length;
1997
 
}
1998
 
 
1999
 
 
2000
 
/*
2001
 
  Mark if the parameter is NULL.
2002
 
 
2003
 
  SYNOPSIS
2004
 
    store_param_null()
2005
 
    net                 MySQL NET connection
2006
 
    param               MySQL bind param
2007
 
 
2008
 
  DESCRIPTION
2009
 
    A data package starts with a string of bits where we set a bit
2010
 
    if a parameter is NULL. Unlike bit string in result set row, here
2011
 
    we don't have reserved bits for OK/error packet.
2012
 
*/
2013
 
 
2014
 
static void store_param_null(NET *net, MYSQL_BIND *param)
2015
 
{
2016
 
  uint pos= param->param_number;
2017
 
  net->buff[pos/8]|=  (uchar) (1 << (pos & 7));
2018
 
}
2019
 
 
2020
 
 
2021
 
/*
2022
 
  Store one parameter in network packet: data is read from
2023
 
  client buffer and saved in network packet by means of one
2024
 
  of store_param_xxxx functions.
2025
 
*/
2026
 
 
2027
 
static my_bool store_param(MYSQL_STMT *stmt, MYSQL_BIND *param)
2028
 
{
2029
 
  NET *net= &stmt->mysql->net;
2030
 
  DBUG_ENTER("store_param");
2031
 
  DBUG_PRINT("enter",("type: %d  buffer: 0x%lx  length: %lu  is_null: %d",
2032
 
                      param->buffer_type,
2033
 
                      (long) (param->buffer ? param->buffer : NullS),
2034
 
                      *param->length, *param->is_null));
2035
 
 
2036
 
  if (*param->is_null)
2037
 
    store_param_null(net, param);
2038
 
  else
2039
 
  {
2040
 
    /*
2041
 
      Param->length should ALWAYS point to the correct length for the type
2042
 
      Either to the length pointer given by the user or param->buffer_length
2043
 
    */
2044
 
    if ((my_realloc_str(net, *param->length)))
2045
 
    {
2046
 
      set_stmt_errmsg(stmt, net);
2047
 
      DBUG_RETURN(1);
2048
 
    }
2049
 
    (*param->store_param_func)(net, param);
2050
 
  }
2051
 
  DBUG_RETURN(0);
2052
 
}
2053
 
 
2054
 
 
2055
 
/*
2056
 
  Auxilary function to send COM_STMT_EXECUTE packet to server and read reply.
2057
 
  Used from cli_stmt_execute, which is in turn used by mysql_stmt_execute.
2058
 
*/
2059
 
 
2060
 
static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
2061
 
{
2062
 
  MYSQL *mysql= stmt->mysql;
2063
 
  NET   *net= &mysql->net;
2064
 
  uchar buff[4 /* size of stmt id */ +
2065
 
             5 /* execution flags */];
2066
 
  my_bool res;
2067
 
  DBUG_ENTER("execute");
2068
 
  DBUG_DUMP("packet", (uchar *) packet, length);
2069
 
 
2070
 
  int4store(buff, stmt->stmt_id);               /* Send stmt id to server */
2071
 
  buff[4]= (char) stmt->flags;
2072
 
  int4store(buff+5, 1);                         /* iteration count */
2073
 
 
2074
 
  res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
2075
 
                                 (uchar*) packet, length, 1, stmt) ||
2076
 
            (*mysql->methods->read_query_result)(mysql));
2077
 
  stmt->affected_rows= mysql->affected_rows;
2078
 
  stmt->server_status= mysql->server_status;
2079
 
  stmt->insert_id= mysql->insert_id;
2080
 
  if (res)
2081
 
  {
2082
 
    set_stmt_errmsg(stmt, net);
2083
 
    DBUG_RETURN(1);
2084
 
  }
2085
 
  DBUG_RETURN(0);
2086
 
}
2087
 
 
2088
 
 
2089
 
int cli_stmt_execute(MYSQL_STMT *stmt)
2090
 
{
2091
 
  DBUG_ENTER("cli_stmt_execute");
2092
 
 
2093
 
  if (stmt->param_count)
2094
 
  {
2095
 
    MYSQL *mysql= stmt->mysql;
2096
 
    NET        *net= &mysql->net;
2097
 
    MYSQL_BIND *param, *param_end;
2098
 
    char       *param_data;
2099
 
    ulong length;
2100
 
    uint null_count;
2101
 
    my_bool    result;
2102
 
 
2103
 
    if (!stmt->bind_param_done)
2104
 
    {
2105
 
      set_stmt_error(stmt, CR_PARAMS_NOT_BOUND, unknown_sqlstate, NULL);
2106
 
      DBUG_RETURN(1);
2107
 
    }
2108
 
    if (mysql->status != MYSQL_STATUS_READY ||
2109
 
        mysql->server_status & SERVER_MORE_RESULTS_EXISTS)
2110
 
    {
2111
 
      set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
2112
 
      DBUG_RETURN(1);
2113
 
    }
2114
 
 
2115
 
    net_clear(net, 1);                          /* Sets net->write_pos */
2116
 
    /* Reserve place for null-marker bytes */
2117
 
    null_count= (stmt->param_count+7) /8;
2118
 
    if (my_realloc_str(net, null_count + 1))
2119
 
    {
2120
 
      set_stmt_errmsg(stmt, net);
2121
 
      DBUG_RETURN(1);
2122
 
    }
2123
 
    bzero((char*) net->write_pos, null_count);
2124
 
    net->write_pos+= null_count;
2125
 
    param_end= stmt->params + stmt->param_count;
2126
 
 
2127
 
    /* In case if buffers (type) altered, indicate to server */
2128
 
    *(net->write_pos)++= (uchar) stmt->send_types_to_server;
2129
 
    if (stmt->send_types_to_server)
2130
 
    {
2131
 
      if (my_realloc_str(net, 2 * stmt->param_count))
2132
 
      {
2133
 
        set_stmt_errmsg(stmt, net);
2134
 
        DBUG_RETURN(1);
2135
 
      }
2136
 
      /*
2137
 
        Store types of parameters in first in first package
2138
 
        that is sent to the server.
2139
 
      */
2140
 
      for (param= stmt->params; param < param_end ; param++)
2141
 
        store_param_type((char**) &net->write_pos, param);
2142
 
    }
2143
 
 
2144
 
    for (param= stmt->params; param < param_end; param++)
2145
 
    {
2146
 
      /* check if mysql_stmt_send_long_data() was used */
2147
 
      if (param->long_data_used)
2148
 
        param->long_data_used= 0;       /* Clear for next execute call */
2149
 
      else if (store_param(stmt, param))
2150
 
        DBUG_RETURN(1);
2151
 
    }
2152
 
    length= (ulong) (net->write_pos - net->buff);
2153
 
    /* TODO: Look into avoding the following memdup */
2154
 
    if (!(param_data= my_memdup(net->buff, length, MYF(0))))
2155
 
    {
2156
 
      set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
2157
 
      DBUG_RETURN(1);
2158
 
    }
2159
 
    result= execute(stmt, param_data, length);
2160
 
    stmt->send_types_to_server=0;
2161
 
    my_free(param_data, MYF(MY_WME));
2162
 
    DBUG_RETURN(result);
2163
 
  }
2164
 
  DBUG_RETURN((int) execute(stmt,0,0));
2165
 
}
2166
 
 
2167
 
/*
2168
 
  Read one row from buffered result set.  Result set is created by prior
2169
 
  call to mysql_stmt_store_result().
2170
 
  SYNOPSIS
2171
 
    stmt_read_row_buffered()
2172
 
 
2173
 
  RETURN VALUE
2174
 
    0             - success; *row is set to valid row pointer (row data
2175
 
                    is stored in result set buffer)
2176
 
    MYSQL_NO_DATA - end of result set. *row is set to NULL
2177
 
*/
2178
 
 
2179
 
static int stmt_read_row_buffered(MYSQL_STMT *stmt, unsigned char **row)
2180
 
{
2181
 
  if (stmt->data_cursor)
2182
 
  {
2183
 
    *row= (uchar *) stmt->data_cursor->data;
2184
 
    stmt->data_cursor= stmt->data_cursor->next;
2185
 
    return 0;
2186
 
  }
2187
 
  *row= 0;
2188
 
  return MYSQL_NO_DATA;
2189
 
}
2190
 
 
2191
1520
/*
2192
1521
  Read one row from network: unbuffered non-cursor fetch.
2193
1522
  If last row was read, or error occured, erase this statement
2254
1583
 
2255
1584
 
2256
1585
/*
2257
 
  Fetch statement row using server side cursor.
2258
 
 
2259
 
  SYNOPSIS
2260
 
    stmt_read_row_from_cursor()
2261
 
 
2262
 
  RETURN VALUE
2263
 
    0            success
2264
 
    1            error
2265
 
  MYSQL_NO_DATA  end of data
2266
 
*/
2267
 
 
2268
 
static int
2269
 
stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
2270
 
{
2271
 
  if (stmt->data_cursor)
2272
 
    return stmt_read_row_buffered(stmt, row);
2273
 
  if (stmt->server_status & SERVER_STATUS_LAST_ROW_SENT)
2274
 
    stmt->server_status &= ~SERVER_STATUS_LAST_ROW_SENT;
2275
 
  else
2276
 
  {
2277
 
    MYSQL *mysql= stmt->mysql;
2278
 
    NET *net= &mysql->net;
2279
 
    MYSQL_DATA *result= &stmt->result;
2280
 
    uchar buff[4 /* statement id */ +
2281
 
               4 /* number of rows to fetch */];
2282
 
 
2283
 
    free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
2284
 
    result->data= NULL;
2285
 
    result->rows= 0;
2286
 
    /* Send row request to the server */
2287
 
    int4store(buff, stmt->stmt_id);
2288
 
    int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */
2289
 
    if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
2290
 
                                            buff, sizeof(buff), (uchar*) 0, 0,
2291
 
                                            1, stmt))
2292
 
    {
2293
 
      set_stmt_errmsg(stmt, net);
2294
 
      return 1;
2295
 
    }
2296
 
    if ((*mysql->methods->read_rows_from_cursor)(stmt))
2297
 
      return 1;
2298
 
    stmt->server_status= mysql->server_status;
2299
 
 
2300
 
    stmt->data_cursor= result->data;
2301
 
    return stmt_read_row_buffered(stmt, row);
2302
 
  }
2303
 
  *row= 0;
2304
 
  return MYSQL_NO_DATA;
2305
 
}
2306
 
 
2307
 
 
2308
 
/*
2309
1586
  Default read row function to not SIGSEGV in client in
2310
1587
  case of wrong sequence of API calls.
2311
1588
*/
2326
1603
}
2327
1604
 
2328
1605
 
2329
 
/*
2330
 
  Get/set statement attributes
2331
 
 
2332
 
  SYNOPSIS
2333
 
    mysql_stmt_attr_get()
2334
 
    mysql_stmt_attr_set()
2335
 
 
2336
 
    attr_type  statement attribute
2337
 
    value      casted to const void * pointer to value.
2338
 
 
2339
 
  RETURN VALUE
2340
 
    0 success
2341
 
   !0 wrong attribute type
2342
 
*/
2343
 
 
2344
 
my_bool STDCALL mysql_stmt_attr_set(MYSQL_STMT *stmt,
2345
 
                                    enum enum_stmt_attr_type attr_type,
2346
 
                                    const void *value)
2347
 
{
2348
 
  switch (attr_type) {
2349
 
  case STMT_ATTR_UPDATE_MAX_LENGTH:
2350
 
    stmt->update_max_length= value ? *(const my_bool*) value : 0;
2351
 
    break;
2352
 
  case STMT_ATTR_CURSOR_TYPE:
2353
 
  {
2354
 
    ulong cursor_type;
2355
 
    cursor_type= value ? *(ulong*) value : 0UL;
2356
 
    if (cursor_type > (ulong) CURSOR_TYPE_READ_ONLY)
2357
 
      goto err_not_implemented;
2358
 
    stmt->flags= cursor_type;
2359
 
    break;
2360
 
  }
2361
 
  case STMT_ATTR_PREFETCH_ROWS:
2362
 
  {
2363
 
    ulong prefetch_rows= value ? *(ulong*) value : DEFAULT_PREFETCH_ROWS;
2364
 
    if (value == 0)
2365
 
      return TRUE;
2366
 
    stmt->prefetch_rows= prefetch_rows;
2367
 
    break;
2368
 
  }
2369
 
  default:
2370
 
    goto err_not_implemented;
2371
 
  }
2372
 
  return FALSE;
2373
 
err_not_implemented:
2374
 
  set_stmt_error(stmt, CR_NOT_IMPLEMENTED, unknown_sqlstate, NULL);
2375
 
  return TRUE;
2376
 
}
2377
 
 
2378
 
 
2379
 
my_bool STDCALL mysql_stmt_attr_get(MYSQL_STMT *stmt,
2380
 
                                    enum enum_stmt_attr_type attr_type,
2381
 
                                    void *value)
2382
 
{
2383
 
  switch (attr_type) {
2384
 
  case STMT_ATTR_UPDATE_MAX_LENGTH:
2385
 
    *(my_bool*) value= stmt->update_max_length;
2386
 
    break;
2387
 
  case STMT_ATTR_CURSOR_TYPE:
2388
 
    *(ulong*) value= stmt->flags;
2389
 
    break;
2390
 
  case STMT_ATTR_PREFETCH_ROWS:
2391
 
    *(ulong*) value= stmt->prefetch_rows;
2392
 
    break;
2393
 
  default:
2394
 
    return TRUE;
2395
 
  }
2396
 
  return FALSE;
2397
 
}
2398
 
 
2399
 
 
2400
 
/*
2401
 
  Send placeholders data to server (if there are placeholders)
2402
 
  and execute prepared statement.
2403
 
 
2404
 
  SYNOPSIS
2405
 
    mysql_stmt_execute()
2406
 
    stmt  statement handle. The handle must be created
2407
 
          with mysql_stmt_init() and prepared with
2408
 
          mysql_stmt_prepare(). If there are placeholders
2409
 
          in the statement they must be bound to local
2410
 
          variables with mysql_stmt_bind_param().
2411
 
 
2412
 
  DESCRIPTION
2413
 
    This function will automatically flush pending result
2414
 
    set (if there is one), send parameters data to the server
2415
 
    and read result of statement execution.
2416
 
    If previous result set was cached with mysql_stmt_store_result()
2417
 
    it will also be freed in the beginning of this call.
2418
 
    The server can return 3 types of responses to this command:
2419
 
    - error, can be retrieved with mysql_stmt_error()
2420
 
    - ok, no result set pending. In this case we just update
2421
 
      stmt->insert_id and stmt->affected_rows.
2422
 
    - the query returns a result set: there could be 0 .. N
2423
 
    rows in it. In this case the server can also send updated
2424
 
    result set metadata.
2425
 
 
2426
 
    Next steps you may want to make:
2427
 
    - find out if there is result set with mysql_stmt_field_count().
2428
 
    If there is one:
2429
 
    - optionally, cache entire result set on client to unblock
2430
 
    connection with mysql_stmt_store_result()
2431
 
    - bind client variables to result set columns and start read rows
2432
 
    with mysql_stmt_fetch().
2433
 
    - reset statement with mysql_stmt_reset() or close it with
2434
 
    mysql_stmt_close()
2435
 
    Otherwise:
2436
 
    - find out last insert id and number of affected rows with
2437
 
    mysql_stmt_insert_id(), mysql_stmt_affected_rows()
2438
 
 
2439
 
  RETURN
2440
 
    0   success
2441
 
    1   error, message can be retrieved with mysql_stmt_error().
2442
 
*/
2443
 
 
2444
 
int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt)
2445
 
{
2446
 
  MYSQL *mysql= stmt->mysql;
2447
 
  DBUG_ENTER("mysql_stmt_execute");
2448
 
 
2449
 
  if (!mysql)
2450
 
  {
2451
 
    /* Error is already set in mysql_detatch_stmt_list */
2452
 
    DBUG_RETURN(1);
2453
 
  }
2454
 
 
2455
 
  if (reset_stmt_handle(stmt, RESET_STORE_RESULT))
2456
 
    DBUG_RETURN(1);
2457
 
  /*
2458
 
    No need to check for stmt->state: if the statement wasn't
2459
 
    prepared we'll get 'unknown statement handler' error from server.
2460
 
  */
2461
 
  if (mysql->methods->stmt_execute(stmt))
2462
 
    DBUG_RETURN(1);
2463
 
  if (mysql->field_count)
2464
 
  {
2465
 
    /* Server has sent result set metadata */
2466
 
    if (stmt->field_count == 0)
2467
 
    {
2468
 
      /*
2469
 
        This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
2470
 
        prepared statements can't send result set metadata for these queries
2471
 
        on prepare stage. Read it now.
2472
 
      */
2473
 
      alloc_stmt_fields(stmt);
2474
 
    }
2475
 
    else
2476
 
    {
2477
 
      /*
2478
 
        Update result set metadata if it for some reason changed between
2479
 
        prepare and execute, i.e.:
2480
 
        - in case of 'SELECT ?' we don't know column type unless data was
2481
 
          supplied to mysql_stmt_execute, so updated column type is sent
2482
 
          now.
2483
 
        - if data dictionary changed between prepare and execute, for
2484
 
          example a table used in the query was altered.
2485
 
        Note, that now (4.1.3) we always send metadata in reply to
2486
 
        COM_STMT_EXECUTE (even if it is not necessary), so either this or
2487
 
        previous branch always works.
2488
 
        TODO: send metadata only when it's really necessary and add a warning
2489
 
        'Metadata changed' when it's sent twice.
2490
 
      */
2491
 
      update_stmt_fields(stmt);
2492
 
    }
2493
 
  }
2494
 
  stmt->state= MYSQL_STMT_EXECUTE_DONE;
2495
 
  if (stmt->field_count)
2496
 
  {
2497
 
    if (stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
2498
 
    {
2499
 
      mysql->status= MYSQL_STATUS_READY;
2500
 
      stmt->read_row_func= stmt_read_row_from_cursor;
2501
 
    }
2502
 
    else if (stmt->flags & CURSOR_TYPE_READ_ONLY)
2503
 
    {
2504
 
      /*
2505
 
        This is a single-row result set, a result set with no rows, EXPLAIN,
2506
 
        SHOW VARIABLES, or some other command which either a) bypasses the
2507
 
        cursors framework in the server and writes rows directly to the
2508
 
        network or b) is more efficient if all (few) result set rows are
2509
 
        precached on client and server's resources are freed.
2510
 
      */
2511
 
      DBUG_RETURN(mysql_stmt_store_result(stmt));
2512
 
    }
2513
 
    else
2514
 
    {
2515
 
      stmt->mysql->unbuffered_fetch_owner= &stmt->unbuffered_fetch_cancelled;
2516
 
      stmt->unbuffered_fetch_cancelled= FALSE;
2517
 
      stmt->read_row_func= stmt_read_row_unbuffered;
2518
 
    }
2519
 
  }
2520
 
  DBUG_RETURN(0);
2521
 
}
2522
 
 
2523
 
 
2524
 
/*
2525
 
  Return total parameters count in the statement
2526
 
*/
2527
 
 
2528
 
ulong STDCALL mysql_stmt_param_count(MYSQL_STMT * stmt)
2529
 
{
2530
 
  DBUG_ENTER("mysql_stmt_param_count");
2531
 
  DBUG_RETURN(stmt->param_count);
2532
 
}
2533
 
 
2534
 
/*
2535
 
  Return total affected rows from the last statement
2536
 
*/
2537
 
 
2538
 
my_ulonglong STDCALL mysql_stmt_affected_rows(MYSQL_STMT *stmt)
2539
 
{
2540
 
  return stmt->affected_rows;
2541
 
}
2542
 
 
2543
 
 
2544
 
/*
2545
 
  Returns the number of result columns for the most recent query
2546
 
  run on this statement.
2547
 
*/
2548
 
 
2549
 
unsigned int STDCALL mysql_stmt_field_count(MYSQL_STMT *stmt)
2550
 
{
2551
 
  return stmt->field_count;
2552
 
}
2553
 
 
2554
 
/*
2555
 
  Return last inserted id for auto_increment columns.
2556
 
 
2557
 
  SYNOPSIS
2558
 
    mysql_stmt_insert_id()
2559
 
    stmt    statement handle
2560
 
 
2561
 
  DESCRIPTION
2562
 
    Current implementation of this call has a caveat: stmt->insert_id is
2563
 
    unconditionally updated from mysql->insert_id in the end of each
2564
 
    mysql_stmt_execute(). This works OK if mysql->insert_id contains new
2565
 
    value (sent in reply to mysql_stmt_execute()), otherwise stmt->insert_id
2566
 
    value gets undefined, as it's updated from some arbitrary value saved in
2567
 
    connection structure during some other call.
2568
 
*/
2569
 
 
2570
 
my_ulonglong STDCALL mysql_stmt_insert_id(MYSQL_STMT *stmt)
2571
 
{
2572
 
  return stmt->insert_id;
2573
 
}
2574
 
 
2575
 
 
2576
1606
static my_bool int_is_null_true= 1;             /* Used for MYSQL_TYPE_NULL */
2577
1607
static my_bool int_is_null_false= 0;
2578
1608
 
2579
 
 
2580
 
/*
2581
 
  Set up input data buffers for a statement.
2582
 
 
2583
 
  SYNOPSIS
2584
 
    mysql_stmt_bind_param()
2585
 
    stmt    statement handle
2586
 
            The statement must be prepared with mysql_stmt_prepare().
2587
 
    my_bind Array of mysql_stmt_param_count() bind parameters.
2588
 
            This function doesn't check that size of this argument
2589
 
            is >= mysql_stmt_field_count(): it's user's responsibility.
2590
 
 
2591
 
  DESCRIPTION
2592
 
    Use this call after mysql_stmt_prepare() to bind user variables to
2593
 
    placeholders.
2594
 
    Each element of bind array stands for a placeholder. Placeholders
2595
 
    are counted from 0.  For example statement
2596
 
    'INSERT INTO t (a, b) VALUES (?, ?)'
2597
 
    contains two placeholders, and for such statement you should supply
2598
 
    bind array of two elements (MYSQL_BIND bind[2]).
2599
 
 
2600
 
    By properly initializing bind array you can bind virtually any
2601
 
    C language type to statement's placeholders:
2602
 
    First, it's strongly recommended to always zero-initialize entire
2603
 
    bind structure before setting its members. This will both shorten
2604
 
    your application code and make it robust to future extensions of
2605
 
    MYSQL_BIND structure.
2606
 
    Then you need to assign typecode of your application buffer to
2607
 
    MYSQL_BIND::buffer_type. The following typecodes with their
2608
 
    correspondence to C language types are supported:
2609
 
    MYSQL_TYPE_TINY       for 8-bit integer variables. Normally it's
2610
 
                          'signed char' and 'unsigned char';
2611
 
    MYSQL_TYPE_SHORT      for 16-bit signed and unsigned variables. This
2612
 
                          is usually 'short' and 'unsigned short';
2613
 
    MYSQL_TYPE_LONG       for 32-bit signed and unsigned variables. It
2614
 
                          corresponds to 'int' and 'unsigned int' on
2615
 
                          vast majority of platforms. On IA-32 and some
2616
 
                          other 32-bit systems you can also use 'long'
2617
 
                          here;
2618
 
    MYSQL_TYPE_LONGLONG   64-bit signed or unsigned integer.  Stands for
2619
 
                          '[unsigned] long long' on most platforms;
2620
 
    MYSQL_TYPE_FLOAT      32-bit floating point type, 'float' on most
2621
 
                          systems;
2622
 
    MYSQL_TYPE_DOUBLE     64-bit floating point type, 'double' on most
2623
 
                          systems;
2624
 
    MYSQL_TYPE_TIME       broken-down time stored in MYSQL_TIME
2625
 
                          structure
2626
 
    MYSQL_TYPE_DATE       date stored in MYSQL_TIME structure
2627
 
    MYSQL_TYPE_DATETIME   datetime stored in MYSQL_TIME structure See
2628
 
                          more on how to use these types for sending
2629
 
                          dates and times below;
2630
 
    MYSQL_TYPE_STRING     character string, assumed to be in
2631
 
                          character-set-client. If character set of
2632
 
                          client is not equal to character set of
2633
 
                          column, value for this placeholder will be
2634
 
                          converted to destination character set before
2635
 
                          insert.
2636
 
    MYSQL_TYPE_BLOB       sequence of bytes. This sequence is assumed to
2637
 
                          be in binary character set (which is the same
2638
 
                          as no particular character set), and is never
2639
 
                          converted to any other character set. See also
2640
 
                          notes about supplying string/blob length
2641
 
                          below.
2642
 
    MYSQL_TYPE_NULL       special typecode for binding nulls.
2643
 
    These C/C++ types are not supported yet by the API: long double,
2644
 
    bool.
2645
 
 
2646
 
    As you can see from the list above, it's responsibility of
2647
 
    application programmer to ensure that chosen typecode properly
2648
 
    corresponds to host language type. For example on all platforms
2649
 
    where we build MySQL packages (as of MySQL 4.1.4) int is a 32-bit
2650
 
    type. So for int you can always assume that proper typecode is
2651
 
    MYSQL_TYPE_LONG (however queer it sounds, the name is legacy of the
2652
 
    old MySQL API). In contrary sizeof(long) can be 4 or 8 8-bit bytes,
2653
 
    depending on platform.
2654
 
 
2655
 
    TODO: provide client typedefs for each integer and floating point
2656
 
    typecode, i. e. int8, uint8, float32, etc.
2657
 
 
2658
 
    Once typecode was set, it's necessary to assign MYSQL_BIND::buffer
2659
 
    to point to the buffer of given type. Finally, additional actions
2660
 
    may be taken for some types or use cases:
2661
 
 
2662
 
    Binding integer types.
2663
 
      For integer types you might also need to set MYSQL_BIND::is_unsigned
2664
 
      member. Set it to TRUE when binding unsigned char, unsigned short,
2665
 
      unsigned int, unsigned long, unsigned long long.
2666
 
 
2667
 
    Binding floating point types.
2668
 
      For floating point types you just need to set
2669
 
      MYSQL_BIND::buffer_type and MYSQL_BIND::buffer. The rest of the
2670
 
      members should be zero-initialized.
2671
 
 
2672
 
    Binding NULLs.
2673
 
      You might have a column always NULL, never NULL, or sometimes
2674
 
      NULL.  For an always NULL column set MYSQL_BIND::buffer_type to
2675
 
      MYSQL_TYPE_NULL.  The rest of the members just need to be
2676
 
      zero-initialized.  For never NULL columns set
2677
 
      MYSQL_BIND::is_null to 0, or this has already been done if you
2678
 
      zero-initialized the entire structure.  If you set
2679
 
      MYSQL_TYPE::is_null to point to an application buffer of type
2680
 
      'my_bool', then this buffer will be checked on each execution:
2681
 
      this way you can set the buffer to TRUE, or any non-0 value for
2682
 
      NULLs, and to FALSE or 0 for not NULL data.
2683
 
 
2684
 
    Binding text strings and sequences of bytes.
2685
 
      For strings, in addition to MYSQL_BIND::buffer_type and
2686
 
      MYSQL_BIND::buffer you need to set MYSQL_BIND::length or
2687
 
      MYSQL_BIND::buffer_length.  If 'length' is set, 'buffer_length'
2688
 
      is ignored. 'buffer_length' member should be used when size of
2689
 
      string doesn't change between executions. If you want to vary
2690
 
      buffer length for each value, set 'length' to point to an
2691
 
      application buffer of type 'unsigned long' and set this long to
2692
 
      length of the string before each mysql_stmt_execute().
2693
 
 
2694
 
    Binding dates and times.
2695
 
      For binding dates and times prepared statements API provides
2696
 
      clients with MYSQL_TIME structure. A pointer to instance of this
2697
 
      structure should be assigned to MYSQL_BIND::buffer whenever
2698
 
      MYSQL_TYPE_TIME, MYSQL_TYPE_DATE, MYSQL_TYPE_DATETIME typecodes
2699
 
      are used.  When typecode is MYSQL_TYPE_TIME, only members
2700
 
      'hour', 'minute', 'second' and 'neg' (is time offset negative)
2701
 
      are used. These members only will be sent to the server.
2702
 
      MYSQL_TYPE_DATE implies use of 'year', 'month', 'day', 'neg'.
2703
 
      MYSQL_TYPE_DATETIME utilizes both parts of MYSQL_TIME structure.
2704
 
      You don't have to set MYSQL_TIME::time_type member: it's not
2705
 
      used when sending data to the server, typecode information is
2706
 
      enough.  'second_part' member can hold microsecond precision of
2707
 
      time value, but now it's only supported on protocol level: you
2708
 
      can't store microsecond in a column, or use in temporal
2709
 
      calculations. However, if you send a time value with microsecond
2710
 
      part for 'SELECT ?', statement, you'll get it back unchanged
2711
 
      from the server.
2712
 
 
2713
 
    Data conversion.
2714
 
      If conversion from host language type to data representation,
2715
 
      corresponding to SQL type, is required it's done on the server.
2716
 
      Data truncation is possible when conversion is lossy. For
2717
 
      example, if you supply MYSQL_TYPE_DATETIME value out of valid
2718
 
      SQL type TIMESTAMP range, the same conversion will be applied as
2719
 
      if this value would have been sent as string in the old
2720
 
      protocol.  TODO: document how the server will behave in case of
2721
 
      truncation/data loss.
2722
 
 
2723
 
    After variables were bound, you can repeatedly set/change their
2724
 
    values and mysql_stmt_execute() the statement.
2725
 
 
2726
 
    See also: mysql_stmt_send_long_data() for sending long text/blob
2727
 
    data in pieces, examples in tests/mysql_client_test.c.
2728
 
    Next steps you might want to make:
2729
 
    - execute statement with mysql_stmt_execute(),
2730
 
    - reset statement using mysql_stmt_reset() or reprepare it with
2731
 
      another query using mysql_stmt_prepare()
2732
 
    - close statement with mysql_stmt_close().
2733
 
 
2734
 
  IMPLEMENTATION
2735
 
    The function copies given bind array to internal storage of the
2736
 
    statement, and sets up typecode-specific handlers to perform
2737
 
    serialization of bound data. This means that although you don't need
2738
 
    to call this routine after each assignment to bind buffers, you
2739
 
    need to call it each time you change parameter typecodes, or other
2740
 
    members of MYSQL_BIND array.
2741
 
    This is a pure local call. Data types of client buffers are sent
2742
 
    along with buffers' data at first execution of the statement.
2743
 
 
2744
 
  RETURN
2745
 
    0  success
2746
 
    1  error, can be retrieved with mysql_stmt_error.
2747
 
*/
2748
 
 
2749
 
my_bool STDCALL mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *my_bind)
2750
 
{
2751
 
  uint count=0;
2752
 
  MYSQL_BIND *param, *end;
2753
 
  DBUG_ENTER("mysql_stmt_bind_param");
2754
 
 
2755
 
  if (!stmt->param_count)
2756
 
  {
2757
 
    if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE)
2758
 
    {
2759
 
      set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate, NULL);
2760
 
      DBUG_RETURN(1);
2761
 
    }
2762
 
    DBUG_RETURN(0);
2763
 
  }
2764
 
 
2765
 
  /* Allocated on prepare */
2766
 
  memcpy((char*) stmt->params, (char*) my_bind,
2767
 
         sizeof(MYSQL_BIND) * stmt->param_count);
2768
 
 
2769
 
  for (param= stmt->params, end= param+stmt->param_count;
2770
 
       param < end ;
2771
 
       param++)
2772
 
  {
2773
 
    param->param_number= count++;
2774
 
    param->long_data_used= 0;
2775
 
 
2776
 
    /* If param->is_null is not set, then the value can never be NULL */
2777
 
    if (!param->is_null)
2778
 
      param->is_null= &int_is_null_false;
2779
 
 
2780
 
    /* Setup data copy functions for the different supported types */
2781
 
    switch (param->buffer_type) {
2782
 
    case MYSQL_TYPE_NULL:
2783
 
      param->is_null= &int_is_null_true;
2784
 
      break;
2785
 
    case MYSQL_TYPE_TINY:
2786
 
      /* Force param->length as this is fixed for this type */
2787
 
      param->length= &param->buffer_length;
2788
 
      param->buffer_length= 1;
2789
 
      param->store_param_func= store_param_tinyint;
2790
 
      break;
2791
 
    case MYSQL_TYPE_SHORT:
2792
 
      param->length= &param->buffer_length;
2793
 
      param->buffer_length= 2;
2794
 
      param->store_param_func= store_param_short;
2795
 
      break;
2796
 
    case MYSQL_TYPE_LONG:
2797
 
      param->length= &param->buffer_length;
2798
 
      param->buffer_length= 4;
2799
 
      param->store_param_func= store_param_int32;
2800
 
      break;
2801
 
    case MYSQL_TYPE_LONGLONG:
2802
 
      param->length= &param->buffer_length;
2803
 
      param->buffer_length= 8;
2804
 
      param->store_param_func= store_param_int64;
2805
 
      break;
2806
 
    case MYSQL_TYPE_FLOAT:
2807
 
      param->length= &param->buffer_length;
2808
 
      param->buffer_length= 4;
2809
 
      param->store_param_func= store_param_float;
2810
 
      break;
2811
 
    case MYSQL_TYPE_DOUBLE:
2812
 
      param->length= &param->buffer_length;
2813
 
      param->buffer_length= 8;
2814
 
      param->store_param_func= store_param_double;
2815
 
      break;
2816
 
    case MYSQL_TYPE_TIME:
2817
 
      param->store_param_func= store_param_time;
2818
 
      param->buffer_length= MAX_TIME_REP_LENGTH;
2819
 
      break;
2820
 
    case MYSQL_TYPE_DATE:
2821
 
      param->store_param_func= store_param_date;
2822
 
      param->buffer_length= MAX_DATE_REP_LENGTH;
2823
 
      break;
2824
 
    case MYSQL_TYPE_DATETIME:
2825
 
    case MYSQL_TYPE_TIMESTAMP:
2826
 
      param->store_param_func= store_param_datetime;
2827
 
      param->buffer_length= MAX_DATETIME_REP_LENGTH;
2828
 
      break;
2829
 
    case MYSQL_TYPE_TINY_BLOB:
2830
 
    case MYSQL_TYPE_MEDIUM_BLOB:
2831
 
    case MYSQL_TYPE_LONG_BLOB:
2832
 
    case MYSQL_TYPE_BLOB:
2833
 
    case MYSQL_TYPE_VARCHAR:
2834
 
    case MYSQL_TYPE_VAR_STRING:
2835
 
    case MYSQL_TYPE_STRING:
2836
 
    case MYSQL_TYPE_DECIMAL:
2837
 
    case MYSQL_TYPE_NEWDECIMAL:
2838
 
      param->store_param_func= store_param_str;
2839
 
      /*
2840
 
        For variable length types user must set either length or
2841
 
        buffer_length.
2842
 
      */
2843
 
      break;
2844
 
    default:
2845
 
      strmov(stmt->sqlstate, unknown_sqlstate);
2846
 
      sprintf(stmt->last_error,
2847
 
              ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
2848
 
              param->buffer_type, count);
2849
 
      DBUG_RETURN(1);
2850
 
    }
2851
 
    /*
2852
 
      If param->length is not given, change it to point to buffer_length.
2853
 
      This way we can always use *param->length to get the length of data
2854
 
    */
2855
 
    if (!param->length)
2856
 
      param->length= &param->buffer_length;
2857
 
  }
2858
 
  /* We have to send/resend type information to MySQL */
2859
 
  stmt->send_types_to_server= TRUE;
2860
 
  stmt->bind_param_done= TRUE;
2861
 
  DBUG_RETURN(0);
2862
 
}
2863
 
 
2864
 
 
2865
 
/********************************************************************
2866
 
 Long data implementation
2867
 
*********************************************************************/
2868
 
 
2869
 
/*
2870
 
  Send long data in pieces to the server
2871
 
 
2872
 
  SYNOPSIS
2873
 
    mysql_stmt_send_long_data()
2874
 
    stmt                        Statement handler
2875
 
    param_number                Parameter number (0 - N-1)
2876
 
    data                        Data to send to server
2877
 
    length                      Length of data to send (may be 0)
2878
 
 
2879
 
  DESCRIPTION
2880
 
    This call can be used repeatedly to send long data in pieces
2881
 
    for any string/binary placeholder. Data supplied for
2882
 
    a placeholder is saved at server side till execute, and then
2883
 
    used instead of value from MYSQL_BIND object. More precisely,
2884
 
    if long data for a parameter was supplied, MYSQL_BIND object
2885
 
    corresponding to this parameter is not sent to server. In the
2886
 
    end of execution long data states of placeholders are reset,
2887
 
    so next time values of such placeholders will be taken again
2888
 
    from MYSQL_BIND array.
2889
 
    The server does not reply to this call: if there was an error
2890
 
    in data handling (which now only can happen if server run out
2891
 
    of memory) it would be returned in reply to
2892
 
    mysql_stmt_execute().
2893
 
    You should choose type of long data carefully if you care
2894
 
    about character set conversions performed by server when the
2895
 
    statement is executed.  No conversion is performed at all for
2896
 
    MYSQL_TYPE_BLOB and other binary typecodes. For
2897
 
    MYSQL_TYPE_STRING and the rest of text placeholders data is
2898
 
    converted from client character set to character set of
2899
 
    connection. If these character sets are different, this
2900
 
    conversion may require additional memory at server, equal to
2901
 
    total size of supplied pieces.
2902
 
 
2903
 
  RETURN VALUES
2904
 
    0   ok
2905
 
    1   error
2906
 
*/
2907
 
 
2908
 
my_bool STDCALL
2909
 
mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
2910
 
                     const char *data, ulong length)
2911
 
{
2912
 
  MYSQL_BIND *param;
2913
 
  DBUG_ENTER("mysql_stmt_send_long_data");
2914
 
  DBUG_ASSERT(stmt != 0);
2915
 
  DBUG_PRINT("enter",("param no: %d  data: 0x%lx, length : %ld",
2916
 
                      param_number, (long) data, length));
2917
 
 
2918
 
  /*
2919
 
    We only need to check for stmt->param_count, if it's not null
2920
 
    prepare was done.
2921
 
  */
2922
 
  if (param_number >= stmt->param_count)
2923
 
  {
2924
 
    set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL);
2925
 
    DBUG_RETURN(1);
2926
 
  }
2927
 
 
2928
 
  param= stmt->params+param_number;
2929
 
  if (!IS_LONGDATA(param->buffer_type))
2930
 
  {
2931
 
    /* Long data handling should be used only for string/binary types */
2932
 
    strmov(stmt->sqlstate, unknown_sqlstate);
2933
 
    sprintf(stmt->last_error, ER(stmt->last_errno= CR_INVALID_BUFFER_USE),
2934
 
            param->param_number);
2935
 
    DBUG_RETURN(1);
2936
 
  }
2937
 
 
2938
 
  /*
2939
 
    Send long data packet if there is data or we're sending long data
2940
 
    for the first time.
2941
 
  */
2942
 
  if (length || param->long_data_used == 0)
2943
 
  {
2944
 
    MYSQL *mysql= stmt->mysql;
2945
 
    /* Packet header: stmt id (4 bytes), param no (2 bytes) */
2946
 
    uchar buff[MYSQL_LONG_DATA_HEADER];
2947
 
 
2948
 
    int4store(buff, stmt->stmt_id);
2949
 
    int2store(buff + 4, param_number);
2950
 
    param->long_data_used= 1;
2951
 
 
2952
 
    /*
2953
 
      Note that we don't get any ok packet from the server in this case
2954
 
      This is intentional to save bandwidth.
2955
 
    */
2956
 
    if ((*mysql->methods->advanced_command)(mysql, COM_STMT_SEND_LONG_DATA,
2957
 
                                            buff, sizeof(buff), (uchar*) data,
2958
 
                                            length, 1, stmt))
2959
 
    {
2960
 
      set_stmt_errmsg(stmt, &mysql->net);
2961
 
      DBUG_RETURN(1);
2962
 
    }
2963
 
  }
2964
 
  DBUG_RETURN(0);
2965
 
}
2966
 
 
2967
 
 
2968
1609
/********************************************************************
2969
1610
 Fetch and conversion of result set rows (binary protocol).
2970
1611
*********************************************************************/
3069
1710
 
3070
1711
 
3071
1712
/*
3072
 
  Convert string to supplied buffer of any type.
3073
 
 
3074
 
  SYNOPSIS
3075
 
    fetch_string_with_conversion()
3076
 
    param   output buffer descriptor
3077
 
    value   column data
3078
 
    length  data length
3079
 
*/
3080
 
 
3081
 
static void fetch_string_with_conversion(MYSQL_BIND *param, char *value,
3082
 
                                         uint length)
3083
 
{
3084
 
  char *buffer= (char *)param->buffer;
3085
 
  int err= 0;
3086
 
  char *endptr= value + length;
3087
 
 
3088
 
  /*
3089
 
    This function should support all target buffer types: the rest
3090
 
    of conversion functions can delegate conversion to it.
3091
 
  */
3092
 
  switch (param->buffer_type) {
3093
 
  case MYSQL_TYPE_NULL: /* do nothing */
3094
 
    break;
3095
 
  case MYSQL_TYPE_TINY:
3096
 
  {
3097
 
    longlong data= my_strtoll10(value, &endptr, &err);
3098
 
    *param->error= (IS_TRUNCATED(data, param->is_unsigned,
3099
 
                                 INT_MIN8, INT_MAX8, UINT_MAX8) || err > 0);
3100
 
    *buffer= (uchar) data;
3101
 
    break;
3102
 
  }
3103
 
  case MYSQL_TYPE_SHORT:
3104
 
  {
3105
 
    longlong data= my_strtoll10(value, &endptr, &err);
3106
 
    *param->error= (IS_TRUNCATED(data, param->is_unsigned,
3107
 
                                 INT_MIN16, INT_MAX16, UINT_MAX16) || err > 0);
3108
 
    shortstore(buffer, (short) data);
3109
 
    break;
3110
 
  }
3111
 
  case MYSQL_TYPE_LONG:
3112
 
  {
3113
 
    longlong data= my_strtoll10(value, &endptr, &err);
3114
 
    *param->error= (IS_TRUNCATED(data, param->is_unsigned,
3115
 
                                 INT_MIN32, INT_MAX32, UINT_MAX32) || err > 0);
3116
 
    longstore(buffer, (int32) data);
3117
 
    break;
3118
 
  }
3119
 
  case MYSQL_TYPE_LONGLONG:
3120
 
  {
3121
 
    longlong data= my_strtoll10(value, &endptr, &err);
3122
 
    *param->error= param->is_unsigned ? err != 0 :
3123
 
                                       (err > 0 || (err == 0 && data < 0));
3124
 
    longlongstore(buffer, data);
3125
 
    break;
3126
 
  }
3127
 
  case MYSQL_TYPE_FLOAT:
3128
 
  {
3129
 
    double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err);
3130
 
    float fdata= (float) data;
3131
 
    *param->error= (fdata != data) | test(err);
3132
 
    floatstore(buffer, fdata);
3133
 
    break;
3134
 
  }
3135
 
  case MYSQL_TYPE_DOUBLE:
3136
 
  {
3137
 
    double data= my_strntod(&my_charset_latin1, value, length, &endptr, &err);
3138
 
    *param->error= test(err);
3139
 
    doublestore(buffer, data);
3140
 
    break;
3141
 
  }
3142
 
  case MYSQL_TYPE_TIME:
3143
 
  {
3144
 
    MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
3145
 
    str_to_time(value, length, tm, &err);
3146
 
    *param->error= test(err);
3147
 
    break;
3148
 
  }
3149
 
  case MYSQL_TYPE_DATE:
3150
 
  case MYSQL_TYPE_DATETIME:
3151
 
  case MYSQL_TYPE_TIMESTAMP:
3152
 
  {
3153
 
    MYSQL_TIME *tm= (MYSQL_TIME *)buffer;
3154
 
    (void) str_to_datetime(value, length, tm, TIME_FUZZY_DATE, &err);
3155
 
    *param->error= test(err) && (param->buffer_type == MYSQL_TYPE_DATE &&
3156
 
                                 tm->time_type != MYSQL_TIMESTAMP_DATE);
3157
 
    break;
3158
 
  }
3159
 
  case MYSQL_TYPE_TINY_BLOB:
3160
 
  case MYSQL_TYPE_MEDIUM_BLOB:
3161
 
  case MYSQL_TYPE_LONG_BLOB:
3162
 
  case MYSQL_TYPE_BLOB:
3163
 
  case MYSQL_TYPE_DECIMAL:
3164
 
  case MYSQL_TYPE_NEWDECIMAL:
3165
 
  default:
3166
 
  {
3167
 
    /*
3168
 
      Copy column data to the buffer taking into account offset,
3169
 
      data length and buffer length.
3170
 
    */
3171
 
    char *start= value + param->offset;
3172
 
    char *end= value + length;
3173
 
    ulong copy_length;
3174
 
    if (start < end)
3175
 
    {
3176
 
      copy_length= end - start;
3177
 
      /* We've got some data beyond offset: copy up to buffer_length bytes */
3178
 
      if (param->buffer_length)
3179
 
        memcpy(buffer, start, min(copy_length, param->buffer_length));
3180
 
    }
3181
 
    else
3182
 
      copy_length= 0;
3183
 
    if (copy_length < param->buffer_length)
3184
 
      buffer[copy_length]= '\0';
3185
 
    *param->error= copy_length > param->buffer_length;
3186
 
    /*
3187
 
      param->length will always contain length of entire column;
3188
 
      number of copied bytes may be way different:
3189
 
    */
3190
 
    *param->length= length;
3191
 
    break;
3192
 
  }
3193
 
  }
3194
 
}
3195
 
 
3196
 
 
3197
 
/*
3198
 
  Convert integer value to client buffer of any type.
3199
 
 
3200
 
  SYNOPSIS
3201
 
    fetch_long_with_conversion()
3202
 
    param   output buffer descriptor
3203
 
    field   column metadata
3204
 
    value   column data
3205
 
*/
3206
 
 
3207
 
static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
3208
 
                                       longlong value, my_bool is_unsigned)
3209
 
{
3210
 
  char *buffer= (char *)param->buffer;
3211
 
 
3212
 
  switch (param->buffer_type) {
3213
 
  case MYSQL_TYPE_NULL: /* do nothing */
3214
 
    break;
3215
 
  case MYSQL_TYPE_TINY:
3216
 
    *param->error= IS_TRUNCATED(value, param->is_unsigned,
3217
 
                                INT_MIN8, INT_MAX8, UINT_MAX8);
3218
 
    *(uchar *)param->buffer= (uchar) value;
3219
 
    break;
3220
 
  case MYSQL_TYPE_SHORT:
3221
 
    *param->error= IS_TRUNCATED(value, param->is_unsigned,
3222
 
                                INT_MIN16, INT_MAX16, UINT_MAX16);
3223
 
    shortstore(buffer, (short) value);
3224
 
    break;
3225
 
  case MYSQL_TYPE_LONG:
3226
 
    *param->error= IS_TRUNCATED(value, param->is_unsigned,
3227
 
                                INT_MIN32, INT_MAX32, UINT_MAX32);
3228
 
    longstore(buffer, (int32) value);
3229
 
    break;
3230
 
  case MYSQL_TYPE_LONGLONG:
3231
 
    longlongstore(buffer, value);
3232
 
    *param->error= param->is_unsigned != is_unsigned && value < 0;
3233
 
    break;
3234
 
  case MYSQL_TYPE_FLOAT:
3235
 
  {
3236
 
    /*
3237
 
      We need to mark the local variable volatile to
3238
 
      workaround Intel FPU executive precision feature.
3239
 
      (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
3240
 
    */
3241
 
    volatile float data;
3242
 
    if (is_unsigned)
3243
 
    {
3244
 
      data= (float) ulonglong2double(value);
3245
 
      *param->error= ((ulonglong) value) != ((ulonglong) data);
3246
 
    }
3247
 
    else
3248
 
    {
3249
 
      data= (float)value;
3250
 
      *param->error= value != ((longlong) data);
3251
 
    }
3252
 
    floatstore(buffer, data);
3253
 
    break;
3254
 
  }
3255
 
  case MYSQL_TYPE_DOUBLE:
3256
 
  {
3257
 
    volatile double data;
3258
 
    if (is_unsigned)
3259
 
    {
3260
 
      data= ulonglong2double(value);
3261
 
      *param->error= ((ulonglong) value) != ((ulonglong) data);
3262
 
    }
3263
 
    else
3264
 
    {
3265
 
      data= (double)value;
3266
 
      *param->error= value != ((longlong) data);
3267
 
    }
3268
 
    doublestore(buffer, data);
3269
 
    break;
3270
 
  }
3271
 
  case MYSQL_TYPE_TIME:
3272
 
  case MYSQL_TYPE_DATE:
3273
 
  case MYSQL_TYPE_TIMESTAMP:
3274
 
  case MYSQL_TYPE_DATETIME:
3275
 
  {
3276
 
    int error;
3277
 
    value= number_to_datetime(value, (MYSQL_TIME *) buffer, TIME_FUZZY_DATE,
3278
 
                              &error);
3279
 
    *param->error= test(error);
3280
 
    break;
3281
 
  }
3282
 
  default:
3283
 
  {
3284
 
    uchar buff[22];                              /* Enough for longlong */
3285
 
    uchar *end= (uchar*) longlong10_to_str(value, (char*) buff,
3286
 
                                           is_unsigned ? 10: -10);
3287
 
    /* Resort to string conversion which supports all typecodes */
3288
 
    uint length= (uint) (end-buff);
3289
 
 
3290
 
    if (field->flags & ZEROFILL_FLAG && length < field->length &&
3291
 
        field->length < 21)
3292
 
    {
3293
 
      bmove_upp(buff+field->length,buff+length, length);
3294
 
      bfill(buff, field->length - length,'0');
3295
 
      length= field->length;
3296
 
    }
3297
 
    fetch_string_with_conversion(param, (char*) buff, length);
3298
 
    break;
3299
 
  }
3300
 
  }
3301
 
}
3302
 
 
3303
 
/*
3304
 
  Convert double/float column to supplied buffer of any type.
3305
 
 
3306
 
  SYNOPSIS
3307
 
    fetch_float_with_conversion()
3308
 
    param   output buffer descriptor
3309
 
    field   column metadata
3310
 
    value   column data
3311
 
    type    either MY_GCVT_ARG_FLOAT or MY_GCVT_ARG_DOUBLE.
3312
 
            Affects the maximum number of significant digits
3313
 
            returned by my_gcvt().
3314
 
*/
3315
 
 
3316
 
static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
3317
 
                                        double value, my_gcvt_arg_type type)
3318
 
{
3319
 
  char *buffer= (char *)param->buffer;
3320
 
  double val64 = (value < 0 ? -floor(-value) : floor(value));
3321
 
 
3322
 
  switch (param->buffer_type) {
3323
 
  case MYSQL_TYPE_NULL: /* do nothing */
3324
 
    break;
3325
 
  case MYSQL_TYPE_TINY:
3326
 
    /*
3327
 
      We need to _store_ data in the buffer before the truncation check to
3328
 
      workaround Intel FPU executive precision feature.
3329
 
      (See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
3330
 
      Sic: AFAIU it does not guarantee to work.
3331
 
    */
3332
 
    if (param->is_unsigned)
3333
 
      *buffer= (uint8) value;
3334
 
    else
3335
 
      *buffer= (int8) value;
3336
 
    *param->error= val64 != (param->is_unsigned ? (double)((uint8) *buffer) :
3337
 
                                                  (double)((int8) *buffer));
3338
 
    break;
3339
 
  case MYSQL_TYPE_SHORT:
3340
 
    if (param->is_unsigned)
3341
 
    {
3342
 
      ushort data= (ushort) value;
3343
 
      shortstore(buffer, data);
3344
 
    }
3345
 
    else
3346
 
    {
3347
 
      short data= (short) value;
3348
 
      shortstore(buffer, data);
3349
 
    }
3350
 
    *param->error= val64 != (param->is_unsigned ? (double) (*(ushort*) buffer):
3351
 
                                                  (double) (*(short*) buffer));
3352
 
    break;
3353
 
  case MYSQL_TYPE_LONG:
3354
 
    if (param->is_unsigned)
3355
 
    {
3356
 
      uint32 data= (uint32) value;
3357
 
      longstore(buffer, data);
3358
 
    }
3359
 
    else
3360
 
    {
3361
 
      int32 data= (int32) value;
3362
 
      longstore(buffer, data);
3363
 
    }
3364
 
    *param->error= val64 != (param->is_unsigned ? (double) (*(uint32*) buffer):
3365
 
                                                  (double) (*(int32*) buffer));
3366
 
      break;
3367
 
  case MYSQL_TYPE_LONGLONG:
3368
 
    if (param->is_unsigned)
3369
 
    {
3370
 
      ulonglong data= (ulonglong) value;
3371
 
      longlongstore(buffer, data);
3372
 
    }
3373
 
    else
3374
 
    {
3375
 
      longlong data= (longlong) value;
3376
 
      longlongstore(buffer, data);
3377
 
    }
3378
 
    *param->error= val64 != (param->is_unsigned ?
3379
 
                             ulonglong2double(*(ulonglong*) buffer) :
3380
 
                             (double) (*(longlong*) buffer));
3381
 
    break;
3382
 
  case MYSQL_TYPE_FLOAT:
3383
 
  {
3384
 
    float data= (float) value;
3385
 
    floatstore(buffer, data);
3386
 
    *param->error= (*(float*) buffer) != value;
3387
 
    break;
3388
 
  }
3389
 
  case MYSQL_TYPE_DOUBLE:
3390
 
  {
3391
 
    doublestore(buffer, value);
3392
 
    break;
3393
 
  }
3394
 
  default:
3395
 
  {
3396
 
    /*
3397
 
      Resort to fetch_string_with_conversion: this should handle
3398
 
      floating point -> string conversion nicely, honor all typecodes
3399
 
      and param->offset possibly set in mysql_stmt_fetch_column
3400
 
    */
3401
 
    char buff[FLOATING_POINT_BUFFER];
3402
 
    size_t len;
3403
 
    if (field->decimals >= NOT_FIXED_DEC)
3404
 
      len= my_gcvt(value, type,
3405
 
                   (int) min(sizeof(buff)-1, param->buffer_length),
3406
 
                   buff, NULL);
3407
 
    else
3408
 
      len= my_fcvt(value, (int) field->decimals, buff, NULL);
3409
 
 
3410
 
    if (field->flags & ZEROFILL_FLAG && len < field->length &&
3411
 
        field->length < MAX_DOUBLE_STRING_REP_LENGTH - 1)
3412
 
    {
3413
 
      bmove_upp((uchar*) buff + field->length, (uchar*) buff + len,
3414
 
                len);
3415
 
      bfill((char*) buff, field->length - len, '0');
3416
 
      len= field->length;
3417
 
    }
3418
 
    fetch_string_with_conversion(param, buff, len);
3419
 
 
3420
 
    break;
3421
 
  }
3422
 
  }
3423
 
}
3424
 
 
3425
 
 
3426
 
/*
3427
 
  Fetch time/date/datetime to supplied buffer of any type
3428
 
 
3429
 
  SYNOPSIS
3430
 
    param   output buffer descriptor
3431
 
    time    column data
3432
 
*/
3433
 
 
3434
 
static void fetch_datetime_with_conversion(MYSQL_BIND *param,
3435
 
                                           MYSQL_FIELD *field,
3436
 
                                           MYSQL_TIME *my_time)
3437
 
{
3438
 
  switch (param->buffer_type) {
3439
 
  case MYSQL_TYPE_NULL: /* do nothing */
3440
 
    break;
3441
 
  case MYSQL_TYPE_DATE:
3442
 
    *(MYSQL_TIME *)(param->buffer)= *my_time;
3443
 
    *param->error= my_time->time_type != MYSQL_TIMESTAMP_DATE;
3444
 
    break;
3445
 
  case MYSQL_TYPE_TIME:
3446
 
    *(MYSQL_TIME *)(param->buffer)= *my_time;
3447
 
    *param->error= my_time->time_type != MYSQL_TIMESTAMP_TIME;
3448
 
    break;
3449
 
  case MYSQL_TYPE_DATETIME:
3450
 
  case MYSQL_TYPE_TIMESTAMP:
3451
 
    *(MYSQL_TIME *)(param->buffer)= *my_time;
3452
 
    /* No error: time and date are compatible with datetime */
3453
 
    break;
3454
 
  case MYSQL_TYPE_YEAR:
3455
 
    shortstore(param->buffer, my_time->year);
3456
 
    *param->error= 1;
3457
 
    break;
3458
 
  case MYSQL_TYPE_FLOAT:
3459
 
  case MYSQL_TYPE_DOUBLE:
3460
 
  {
3461
 
    ulonglong value= TIME_to_ulonglong(my_time);
3462
 
    fetch_float_with_conversion(param, field,
3463
 
                                ulonglong2double(value), MY_GCVT_ARG_DOUBLE);
3464
 
    break;
3465
 
  }
3466
 
  case MYSQL_TYPE_TINY:
3467
 
  case MYSQL_TYPE_SHORT:
3468
 
  case MYSQL_TYPE_INT24:
3469
 
  case MYSQL_TYPE_LONG:
3470
 
  case MYSQL_TYPE_LONGLONG:
3471
 
  {
3472
 
    longlong value= (longlong) TIME_to_ulonglong(my_time);
3473
 
    fetch_long_with_conversion(param, field, value, TRUE);
3474
 
    break;
3475
 
  }
3476
 
  default:
3477
 
  {
3478
 
    /*
3479
 
      Convert time value  to string and delegate the rest to
3480
 
      fetch_string_with_conversion:
3481
 
    */
3482
 
    char buff[MAX_DATE_STRING_REP_LENGTH];
3483
 
    uint length= my_TIME_to_str(my_time, buff);
3484
 
    /* Resort to string conversion */
3485
 
    fetch_string_with_conversion(param, (char *)buff, length);
3486
 
    break;
3487
 
  }
3488
 
  }
3489
 
}
3490
 
 
3491
 
 
3492
 
/*
3493
 
  Fetch and convert result set column to output buffer.
3494
 
 
3495
 
  SYNOPSIS
3496
 
    fetch_result_with_conversion()
3497
 
    param   output buffer descriptor
3498
 
    field   column metadata
3499
 
    row     points to a column of result set tuple in binary format
3500
 
 
3501
 
  DESCRIPTION
3502
 
    This is a fallback implementation of column fetch used
3503
 
    if column and output buffer types do not match.
3504
 
    Increases tuple pointer to point at the next column within the
3505
 
    tuple.
3506
 
*/
3507
 
 
3508
 
static void fetch_result_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
3509
 
                                         uchar **row)
3510
 
{
3511
 
  enum enum_field_types field_type= field->type;
3512
 
  uint field_is_unsigned= field->flags & UNSIGNED_FLAG;
3513
 
 
3514
 
  switch (field_type) {
3515
 
  case MYSQL_TYPE_TINY:
3516
 
  {
3517
 
    uchar value= **row;
3518
 
    /* sic: we need to cast to 'signed char' as 'char' may be unsigned */
3519
 
    longlong data= field_is_unsigned ? (longlong) value :
3520
 
                                       (longlong) (signed char) value;
3521
 
    fetch_long_with_conversion(param, field, data, 0);
3522
 
    *row+= 1;
3523
 
    break;
3524
 
  }
3525
 
  case MYSQL_TYPE_SHORT:
3526
 
  case MYSQL_TYPE_YEAR:
3527
 
  {
3528
 
    short value= sint2korr(*row);
3529
 
    longlong data= field_is_unsigned ? (longlong) (unsigned short) value :
3530
 
                                       (longlong) value;
3531
 
    fetch_long_with_conversion(param, field, data, 0);
3532
 
    *row+= 2;
3533
 
    break;
3534
 
  }
3535
 
  case MYSQL_TYPE_INT24: /* mediumint is sent as 4 bytes int */
3536
 
  case MYSQL_TYPE_LONG:
3537
 
  {
3538
 
    int32 value= sint4korr(*row);
3539
 
    longlong data= field_is_unsigned ? (longlong) (uint32) value :
3540
 
                                       (longlong) value;
3541
 
    fetch_long_with_conversion(param, field, data, 0);
3542
 
    *row+= 4;
3543
 
    break;
3544
 
  }
3545
 
  case MYSQL_TYPE_LONGLONG:
3546
 
  {
3547
 
    longlong value= (longlong)sint8korr(*row);
3548
 
    fetch_long_with_conversion(param, field, value,
3549
 
                               field->flags & UNSIGNED_FLAG);
3550
 
    *row+= 8;
3551
 
    break;
3552
 
  }
3553
 
  case MYSQL_TYPE_FLOAT:
3554
 
  {
3555
 
    float value;
3556
 
    float4get(value,*row);
3557
 
    fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_FLOAT);
3558
 
    *row+= 4;
3559
 
    break;
3560
 
  }
3561
 
  case MYSQL_TYPE_DOUBLE:
3562
 
  {
3563
 
    double value;
3564
 
    float8get(value,*row);
3565
 
    fetch_float_with_conversion(param, field, value, MY_GCVT_ARG_DOUBLE);
3566
 
    *row+= 8;
3567
 
    break;
3568
 
  }
3569
 
  case MYSQL_TYPE_DATE:
3570
 
  {
3571
 
    MYSQL_TIME tm;
3572
 
 
3573
 
    read_binary_date(&tm, row);
3574
 
    fetch_datetime_with_conversion(param, field, &tm);
3575
 
    break;
3576
 
  }
3577
 
  case MYSQL_TYPE_TIME:
3578
 
  {
3579
 
    MYSQL_TIME tm;
3580
 
 
3581
 
    read_binary_time(&tm, row);
3582
 
    fetch_datetime_with_conversion(param, field, &tm);
3583
 
    break;
3584
 
  }
3585
 
  case MYSQL_TYPE_DATETIME:
3586
 
  case MYSQL_TYPE_TIMESTAMP:
3587
 
  {
3588
 
    MYSQL_TIME tm;
3589
 
 
3590
 
    read_binary_datetime(&tm, row);
3591
 
    fetch_datetime_with_conversion(param, field, &tm);
3592
 
    break;
3593
 
  }
3594
 
  default:
3595
 
  {
3596
 
    ulong length= net_field_length(row);
3597
 
    fetch_string_with_conversion(param, (char*) *row, length);
3598
 
    *row+= length;
3599
 
    break;
3600
 
  }
3601
 
  }
3602
 
}
3603
 
 
3604
 
 
3605
 
/*
3606
 
  Functions to fetch data to application buffers without conversion.
3607
 
 
3608
 
  All functions have the following characteristics:
3609
 
 
3610
 
  SYNOPSIS
3611
 
    fetch_result_xxx()
3612
 
    param   MySQL bind param
3613
 
    pos     Row value
3614
 
 
3615
 
  DESCRIPTION
3616
 
    These are no-conversion functions, used in binary protocol to store
3617
 
    rows in application buffers. A function used only if type of binary data
3618
 
    is compatible with type of application buffer.
3619
 
 
3620
 
  RETURN
3621
 
    none
3622
 
*/
3623
 
 
3624
 
static void fetch_result_tinyint(MYSQL_BIND *param, MYSQL_FIELD *field,
3625
 
                                 uchar **row)
3626
 
{
3627
 
  my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
3628
 
  uchar data= **row;
3629
 
  *(uchar *)param->buffer= data;
3630
 
  *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX8;
3631
 
  (*row)++;
3632
 
}
3633
 
 
3634
 
static void fetch_result_short(MYSQL_BIND *param, MYSQL_FIELD *field,
3635
 
                               uchar **row)
3636
 
{
3637
 
  my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
3638
 
  ushort data= (ushort) sint2korr(*row);
3639
 
  shortstore(param->buffer, data);
3640
 
  *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX16;
3641
 
  *row+= 2;
3642
 
}
3643
 
 
3644
 
static void fetch_result_int32(MYSQL_BIND *param,
3645
 
                               MYSQL_FIELD *field __attribute__((unused)),
3646
 
                               uchar **row)
3647
 
{
3648
 
  my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
3649
 
  uint32 data= (uint32) sint4korr(*row);
3650
 
  longstore(param->buffer, data);
3651
 
  *param->error= param->is_unsigned != field_is_unsigned && data > INT_MAX32;
3652
 
  *row+= 4;
3653
 
}
3654
 
 
3655
 
static void fetch_result_int64(MYSQL_BIND *param,
3656
 
                               MYSQL_FIELD *field __attribute__((unused)),
3657
 
                               uchar **row)
3658
 
{
3659
 
  my_bool field_is_unsigned= test(field->flags & UNSIGNED_FLAG);
3660
 
  ulonglong data= (ulonglong) sint8korr(*row);
3661
 
  *param->error= param->is_unsigned != field_is_unsigned && data > LONGLONG_MAX;
3662
 
  longlongstore(param->buffer, data);
3663
 
  *row+= 8;
3664
 
}
3665
 
 
3666
 
static void fetch_result_float(MYSQL_BIND *param,
3667
 
                               MYSQL_FIELD *field __attribute__((unused)),
3668
 
                               uchar **row)
3669
 
{
3670
 
  float value;
3671
 
  float4get(value,*row);
3672
 
  floatstore(param->buffer, value);
3673
 
  *row+= 4;
3674
 
}
3675
 
 
3676
 
static void fetch_result_double(MYSQL_BIND *param,
3677
 
                                MYSQL_FIELD *field __attribute__((unused)),
3678
 
                                uchar **row)
3679
 
{
3680
 
  double value;
3681
 
  float8get(value,*row);
3682
 
  doublestore(param->buffer, value);
3683
 
  *row+= 8;
3684
 
}
3685
 
 
3686
 
static void fetch_result_time(MYSQL_BIND *param,
3687
 
                              MYSQL_FIELD *field __attribute__((unused)),
3688
 
                              uchar **row)
3689
 
{
3690
 
  MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
3691
 
  read_binary_time(tm, row);
3692
 
}
3693
 
 
3694
 
static void fetch_result_date(MYSQL_BIND *param,
3695
 
                              MYSQL_FIELD *field __attribute__((unused)),
3696
 
                              uchar **row)
3697
 
{
3698
 
  MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
3699
 
  read_binary_date(tm, row);
3700
 
}
3701
 
 
3702
 
static void fetch_result_datetime(MYSQL_BIND *param,
3703
 
                                  MYSQL_FIELD *field __attribute__((unused)),
3704
 
                                  uchar **row)
3705
 
{
3706
 
  MYSQL_TIME *tm= (MYSQL_TIME *)param->buffer;
3707
 
  read_binary_datetime(tm, row);
3708
 
}
3709
 
 
3710
 
static void fetch_result_bin(MYSQL_BIND *param,
3711
 
                             MYSQL_FIELD *field __attribute__((unused)),
3712
 
                             uchar **row)
3713
 
{
3714
 
  ulong length= net_field_length(row);
3715
 
  ulong copy_length= min(length, param->buffer_length);
3716
 
  memcpy(param->buffer, (char *)*row, copy_length);
3717
 
  *param->length= length;
3718
 
  *param->error= copy_length < length;
3719
 
  *row+= length;
3720
 
}
3721
 
 
3722
 
static void fetch_result_str(MYSQL_BIND *param,
3723
 
                             MYSQL_FIELD *field __attribute__((unused)),
3724
 
                             uchar **row)
3725
 
{
3726
 
  ulong length= net_field_length(row);
3727
 
  ulong copy_length= min(length, param->buffer_length);
3728
 
  memcpy(param->buffer, (char *)*row, copy_length);
3729
 
  /* Add an end null if there is room in the buffer */
3730
 
  if (copy_length != param->buffer_length)
3731
 
    ((uchar *)param->buffer)[copy_length]= '\0';
3732
 
  *param->length= length;                       /* return total length */
3733
 
  *param->error= copy_length < length;
3734
 
  *row+= length;
3735
 
}
3736
 
 
3737
 
 
3738
 
/*
3739
 
  functions to calculate max lengths for strings during
3740
 
  mysql_stmt_store_result()
3741
 
*/
3742
 
 
3743
 
static void skip_result_fixed(MYSQL_BIND *param,
3744
 
                              MYSQL_FIELD *field __attribute__((unused)),
3745
 
                              uchar **row)
3746
 
 
3747
 
{
3748
 
  (*row)+= param->pack_length;
3749
 
}
3750
 
 
3751
 
 
3752
 
static void skip_result_with_length(MYSQL_BIND *param __attribute__((unused)),
3753
 
                                    MYSQL_FIELD *field __attribute__((unused)),
3754
 
                                    uchar **row)
3755
 
 
3756
 
{
3757
 
  ulong length= net_field_length(row);
3758
 
  (*row)+= length;
3759
 
}
3760
 
 
3761
 
 
3762
 
static void skip_result_string(MYSQL_BIND *param __attribute__((unused)),
3763
 
                               MYSQL_FIELD *field,
3764
 
                               uchar **row)
3765
 
 
3766
 
{
3767
 
  ulong length= net_field_length(row);
3768
 
  (*row)+= length;
3769
 
  if (field->max_length < length)
3770
 
    field->max_length= length;
3771
 
}
3772
 
 
3773
 
 
3774
 
/*
3775
1713
  Check that two field types are binary compatible i. e.
3776
1714
  have equal representation in the binary protocol and
3777
1715
  require client-side buffers of the same type.
3819
1757
}
3820
1758
 
3821
1759
 
3822
 
/*
3823
 
  Setup a fetch function for one column of a result set.
3824
 
 
3825
 
  SYNOPSIS
3826
 
    setup_one_fetch_function()
3827
 
    param    output buffer descriptor
3828
 
    field    column descriptor
3829
 
 
3830
 
  DESCRIPTION
3831
 
    When user binds result set buffers or when result set
3832
 
    metadata is changed, we need to setup fetch (and possibly
3833
 
    conversion) functions for all columns of the result set.
3834
 
    In addition to that here we set up skip_result function, used
3835
 
    to update result set metadata in case when
3836
 
    STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
3837
 
    Notice that while fetch_result is chosen depending on both
3838
 
    field->type and param->type, skip_result depends on field->type
3839
 
    only.
3840
 
 
3841
 
  RETURN
3842
 
    TRUE   fetch function for this typecode was not found (typecode
3843
 
          is not supported by the client library)
3844
 
    FALSE  success
3845
 
*/
3846
 
 
3847
 
static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
3848
 
{
3849
 
  DBUG_ENTER("setup_one_fetch_function");
3850
 
 
3851
 
  /* Setup data copy functions for the different supported types */
3852
 
  switch (param->buffer_type) {
3853
 
  case MYSQL_TYPE_NULL: /* for dummy binds */
3854
 
    /*
3855
 
      It's not binary compatible with anything the server can return:
3856
 
      no need to setup fetch_result, as it'll be reset anyway
3857
 
    */
3858
 
    *param->length= 0;
3859
 
    break;
3860
 
  case MYSQL_TYPE_TINY:
3861
 
    param->fetch_result= fetch_result_tinyint;
3862
 
    *param->length= 1;
3863
 
    break;
3864
 
  case MYSQL_TYPE_SHORT:
3865
 
  case MYSQL_TYPE_YEAR:
3866
 
    param->fetch_result= fetch_result_short;
3867
 
    *param->length= 2;
3868
 
    break;
3869
 
  case MYSQL_TYPE_INT24:
3870
 
  case MYSQL_TYPE_LONG:
3871
 
    param->fetch_result= fetch_result_int32;
3872
 
    *param->length= 4;
3873
 
    break;
3874
 
  case MYSQL_TYPE_LONGLONG:
3875
 
    param->fetch_result= fetch_result_int64;
3876
 
    *param->length= 8;
3877
 
    break;
3878
 
  case MYSQL_TYPE_FLOAT:
3879
 
    param->fetch_result= fetch_result_float;
3880
 
    *param->length= 4;
3881
 
    break;
3882
 
  case MYSQL_TYPE_DOUBLE:
3883
 
    param->fetch_result= fetch_result_double;
3884
 
    *param->length= 8;
3885
 
    break;
3886
 
  case MYSQL_TYPE_TIME:
3887
 
    param->fetch_result= fetch_result_time;
3888
 
    *param->length= sizeof(MYSQL_TIME);
3889
 
    break;
3890
 
  case MYSQL_TYPE_DATE:
3891
 
    param->fetch_result= fetch_result_date;
3892
 
    *param->length= sizeof(MYSQL_TIME);
3893
 
    break;
3894
 
  case MYSQL_TYPE_DATETIME:
3895
 
  case MYSQL_TYPE_TIMESTAMP:
3896
 
    param->fetch_result= fetch_result_datetime;
3897
 
    *param->length= sizeof(MYSQL_TIME);
3898
 
    break;
3899
 
  case MYSQL_TYPE_TINY_BLOB:
3900
 
  case MYSQL_TYPE_MEDIUM_BLOB:
3901
 
  case MYSQL_TYPE_LONG_BLOB:
3902
 
  case MYSQL_TYPE_BLOB:
3903
 
  case MYSQL_TYPE_BIT:
3904
 
    DBUG_ASSERT(param->buffer_length != 0);
3905
 
    param->fetch_result= fetch_result_bin;
3906
 
    break;
3907
 
  case MYSQL_TYPE_VAR_STRING:
3908
 
  case MYSQL_TYPE_STRING:
3909
 
  case MYSQL_TYPE_DECIMAL:
3910
 
  case MYSQL_TYPE_NEWDECIMAL:
3911
 
  case MYSQL_TYPE_NEWDATE:
3912
 
    DBUG_ASSERT(param->buffer_length != 0);
3913
 
    param->fetch_result= fetch_result_str;
3914
 
    break;
3915
 
  default:
3916
 
    DBUG_PRINT("error", ("Unknown param->buffer_type: %u",
3917
 
                         (uint) param->buffer_type));
3918
 
    DBUG_RETURN(TRUE);
3919
 
  }
3920
 
  if (! is_binary_compatible(param->buffer_type, field->type))
3921
 
    param->fetch_result= fetch_result_with_conversion;
3922
 
 
3923
 
  /* Setup skip_result functions (to calculate max_length) */
3924
 
  param->skip_result= skip_result_fixed;
3925
 
  switch (field->type) {
3926
 
  case MYSQL_TYPE_NULL: /* for dummy binds */
3927
 
    param->pack_length= 0;
3928
 
    field->max_length= 0;
3929
 
    break;
3930
 
  case MYSQL_TYPE_TINY:
3931
 
    param->pack_length= 1;
3932
 
    field->max_length= 4;                     /* as in '-127' */
3933
 
    break;
3934
 
  case MYSQL_TYPE_YEAR:
3935
 
  case MYSQL_TYPE_SHORT:
3936
 
    param->pack_length= 2;
3937
 
    field->max_length= 6;                     /* as in '-32767' */
3938
 
    break;
3939
 
  case MYSQL_TYPE_INT24:
3940
 
    field->max_length= 9;  /* as in '16777216' or in '-8388607' */
3941
 
    param->pack_length= 4;
3942
 
    break;
3943
 
  case MYSQL_TYPE_LONG:
3944
 
    field->max_length= 11;                    /* '-2147483647' */
3945
 
    param->pack_length= 4;
3946
 
    break;
3947
 
  case MYSQL_TYPE_LONGLONG:
3948
 
    field->max_length= 21;                    /* '18446744073709551616' */
3949
 
    param->pack_length= 8;
3950
 
    break;
3951
 
  case MYSQL_TYPE_FLOAT:
3952
 
    param->pack_length= 4;
3953
 
    field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
3954
 
    break;
3955
 
  case MYSQL_TYPE_DOUBLE:
3956
 
    param->pack_length= 8;
3957
 
    field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
3958
 
    break;
3959
 
  case MYSQL_TYPE_TIME:
3960
 
    field->max_length= 15;                    /* 19:23:48.123456 */
3961
 
    param->skip_result= skip_result_with_length;
3962
 
  case MYSQL_TYPE_DATE:
3963
 
    field->max_length= 10;                    /* 2003-11-11 */
3964
 
    param->skip_result= skip_result_with_length;
3965
 
    break;
3966
 
    break;
3967
 
  case MYSQL_TYPE_DATETIME:
3968
 
  case MYSQL_TYPE_TIMESTAMP:
3969
 
    param->skip_result= skip_result_with_length;
3970
 
    field->max_length= MAX_DATE_STRING_REP_LENGTH;
3971
 
    break;
3972
 
  case MYSQL_TYPE_DECIMAL:
3973
 
  case MYSQL_TYPE_NEWDECIMAL:
3974
 
  case MYSQL_TYPE_ENUM:
3975
 
  case MYSQL_TYPE_SET:
3976
 
  case MYSQL_TYPE_GEOMETRY:
3977
 
  case MYSQL_TYPE_TINY_BLOB:
3978
 
  case MYSQL_TYPE_MEDIUM_BLOB:
3979
 
  case MYSQL_TYPE_LONG_BLOB:
3980
 
  case MYSQL_TYPE_BLOB:
3981
 
  case MYSQL_TYPE_VAR_STRING:
3982
 
  case MYSQL_TYPE_STRING:
3983
 
  case MYSQL_TYPE_BIT:
3984
 
  case MYSQL_TYPE_NEWDATE:
3985
 
    param->skip_result= skip_result_string;
3986
 
    break;
3987
 
  default:
3988
 
    DBUG_PRINT("error", ("Unknown field->type: %u", (uint) field->type));
3989
 
    DBUG_RETURN(TRUE);
3990
 
  }
3991
 
  DBUG_RETURN(FALSE);
3992
 
}
3993
 
 
3994
 
 
3995
 
/*
3996
 
  Setup the bind buffers for resultset processing
3997
 
*/
3998
 
 
3999
 
my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *my_bind)
4000
 
{
4001
 
  MYSQL_BIND *param, *end;
4002
 
  MYSQL_FIELD *field;
4003
 
  ulong       bind_count= stmt->field_count;
4004
 
  uint        param_count= 0;
4005
 
  DBUG_ENTER("mysql_stmt_bind_result");
4006
 
  DBUG_PRINT("enter",("field_count: %lu", bind_count));
4007
 
 
4008
 
  if (!bind_count)
4009
 
  {
4010
 
    int errorcode= (int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE ?
4011
 
                   CR_NO_PREPARE_STMT : CR_NO_STMT_METADATA;
4012
 
    set_stmt_error(stmt, errorcode, unknown_sqlstate, NULL);
4013
 
    DBUG_RETURN(1);
4014
 
  }
4015
 
 
4016
 
  /*
4017
 
    We only need to check that stmt->field_count - if it is not null
4018
 
    stmt->bind was initialized in mysql_stmt_prepare
4019
 
    stmt->bind overlaps with bind if mysql_stmt_bind_param
4020
 
    is called from mysql_stmt_store_result.
4021
 
  */
4022
 
 
4023
 
  if (stmt->bind != my_bind)
4024
 
    memcpy((char*) stmt->bind, (char*) my_bind,
4025
 
           sizeof(MYSQL_BIND) * bind_count);
4026
 
 
4027
 
  for (param= stmt->bind, end= param + bind_count, field= stmt->fields ;
4028
 
       param < end ;
4029
 
       param++, field++)
4030
 
  {
4031
 
    DBUG_PRINT("info",("buffer_type: %u  field_type: %u",
4032
 
                       (uint) param->buffer_type, (uint) field->type));
4033
 
    /*
4034
 
      Set param->is_null to point to a dummy variable if it's not set.
4035
 
      This is to make the execute code easier
4036
 
    */
4037
 
    if (!param->is_null)
4038
 
      param->is_null= &param->is_null_value;
4039
 
 
4040
 
    if (!param->length)
4041
 
      param->length= &param->length_value;
4042
 
 
4043
 
    if (!param->error)
4044
 
      param->error= &param->error_value;
4045
 
 
4046
 
    param->param_number= param_count++;
4047
 
    param->offset= 0;
4048
 
 
4049
 
    if (setup_one_fetch_function(param, field))
4050
 
    {
4051
 
      strmov(stmt->sqlstate, unknown_sqlstate);
4052
 
      sprintf(stmt->last_error,
4053
 
              ER(stmt->last_errno= CR_UNSUPPORTED_PARAM_TYPE),
4054
 
              field->type, param_count);
4055
 
      DBUG_RETURN(1);
4056
 
    }
4057
 
  }
4058
 
  stmt->bind_result_done= BIND_RESULT_DONE;
4059
 
  if (stmt->mysql->options.report_data_truncation)
4060
 
    stmt->bind_result_done|= REPORT_DATA_TRUNCATION;
4061
 
 
4062
 
  DBUG_RETURN(0);
4063
 
}
4064
 
 
4065
 
 
4066
 
/*
4067
 
  Fetch row data to bind buffers
4068
 
*/
4069
 
 
4070
 
static int stmt_fetch_row(MYSQL_STMT *stmt, uchar *row)
4071
 
{
4072
 
  MYSQL_BIND  *my_bind, *end;
4073
 
  MYSQL_FIELD *field;
4074
 
  uchar *null_ptr, bit;
4075
 
  int truncation_count= 0;
4076
 
  /*
4077
 
    Precondition: if stmt->field_count is zero or row is NULL, read_row_*
4078
 
    function must return no data.
4079
 
  */
4080
 
  DBUG_ASSERT(stmt->field_count);
4081
 
  DBUG_ASSERT(row);
4082
 
 
4083
 
  if (!stmt->bind_result_done)
4084
 
  {
4085
 
    /* If output parameters were not bound we should just return success */
4086
 
    return 0;
4087
 
  }
4088
 
 
4089
 
  null_ptr= row;
4090
 
  row+= (stmt->field_count+9)/8;                /* skip null bits */
4091
 
  bit= 4;                                       /* first 2 bits are reserved */
4092
 
 
4093
 
  /* Copy complete row to application buffers */
4094
 
  for (my_bind= stmt->bind, end= my_bind + stmt->field_count,
4095
 
         field= stmt->fields ;
4096
 
       my_bind < end ;
4097
 
       my_bind++, field++)
4098
 
  {
4099
 
    *my_bind->error= 0;
4100
 
    if (*null_ptr & bit)
4101
 
    {
4102
 
      /*
4103
 
        We should set both row_ptr and is_null to be able to see
4104
 
        nulls in mysql_stmt_fetch_column. This is because is_null may point
4105
 
        to user data which can be overwritten between mysql_stmt_fetch and
4106
 
        mysql_stmt_fetch_column, and in this case nullness of column will be
4107
 
        lost. See mysql_stmt_fetch_column for details.
4108
 
      */
4109
 
      my_bind->row_ptr= NULL;
4110
 
      *my_bind->is_null= 1;
4111
 
    }
4112
 
    else
4113
 
    {
4114
 
      *my_bind->is_null= 0;
4115
 
      my_bind->row_ptr= row;
4116
 
      (*my_bind->fetch_result)(my_bind, field, &row);
4117
 
      truncation_count+= *my_bind->error;
4118
 
    }
4119
 
    if (!((bit<<=1) & 255))
4120
 
    {
4121
 
      bit= 1;                                   /* To next uchar */
4122
 
      null_ptr++;
4123
 
    }
4124
 
  }
4125
 
  if (truncation_count && (stmt->bind_result_done & REPORT_DATA_TRUNCATION))
4126
 
    return MYSQL_DATA_TRUNCATED;
4127
 
  return 0;
4128
 
}
4129
 
 
4130
 
 
4131
1760
int cli_unbuffered_fetch(MYSQL *mysql, char **row)
4132
1761
{
4133
1762
  if (packet_error == cli_safe_read(mysql))
4140
1769
 
4141
1770
 
4142
1771
/*
4143
 
  Fetch and return row data to bound buffers, if any
4144
 
*/
4145
 
 
4146
 
int STDCALL mysql_stmt_fetch(MYSQL_STMT *stmt)
4147
 
{
4148
 
  int rc;
4149
 
  uchar *row;
4150
 
  DBUG_ENTER("mysql_stmt_fetch");
4151
 
 
4152
 
  if ((rc= (*stmt->read_row_func)(stmt, &row)) ||
4153
 
      ((rc= stmt_fetch_row(stmt, row)) && rc != MYSQL_DATA_TRUNCATED))
4154
 
  {
4155
 
    stmt->state= MYSQL_STMT_PREPARE_DONE;       /* XXX: this is buggy */
4156
 
    stmt->read_row_func= (rc == MYSQL_NO_DATA) ? 
4157
 
      stmt_read_row_no_data : stmt_read_row_no_result_set;
4158
 
  }
4159
 
  else
4160
 
  {
4161
 
    /* This is to know in mysql_stmt_fetch_column that data was fetched */
4162
 
    stmt->state= MYSQL_STMT_FETCH_DONE;
4163
 
  }
4164
 
  DBUG_RETURN(rc);
4165
 
}
4166
 
 
4167
 
 
4168
 
/*
4169
 
  Fetch data for one specified column data
4170
 
 
4171
 
  SYNOPSIS
4172
 
    mysql_stmt_fetch_column()
4173
 
    stmt                Prepared statement handler
4174
 
    my_bind             Where data should be placed. Should be filled in as
4175
 
                        when calling mysql_stmt_bind_result()
4176
 
    column              Column to fetch (first column is 0)
4177
 
    ulong offset        Offset in result data (to fetch blob in pieces)
4178
 
                        This is normally 0
4179
 
  RETURN
4180
 
    0   ok
4181
 
    1   error
4182
 
*/
4183
 
 
4184
 
int STDCALL mysql_stmt_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *my_bind,
4185
 
                                    uint column, ulong offset)
4186
 
{
4187
 
  MYSQL_BIND *param= stmt->bind+column;
4188
 
  DBUG_ENTER("mysql_stmt_fetch_column");
4189
 
 
4190
 
  if ((int) stmt->state < (int) MYSQL_STMT_FETCH_DONE)
4191
 
  {
4192
 
    set_stmt_error(stmt, CR_NO_DATA, unknown_sqlstate, NULL);
4193
 
    return 1;
4194
 
  }
4195
 
  if (column >= stmt->field_count)
4196
 
  {
4197
 
    set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate, NULL);
4198
 
    DBUG_RETURN(1);
4199
 
  }
4200
 
 
4201
 
  if (!my_bind->error)
4202
 
    my_bind->error= &my_bind->error_value;
4203
 
  *my_bind->error= 0;
4204
 
  if (param->row_ptr)
4205
 
  {
4206
 
    MYSQL_FIELD *field= stmt->fields+column;
4207
 
    uchar *row= param->row_ptr;
4208
 
    my_bind->offset= offset;
4209
 
    if (my_bind->is_null)
4210
 
      *my_bind->is_null= 0;
4211
 
    if (my_bind->length) /* Set the length if non char/binary types */
4212
 
      *my_bind->length= *param->length;
4213
 
    else
4214
 
      my_bind->length= &param->length_value;       /* Needed for fetch_result() */
4215
 
    fetch_result_with_conversion(my_bind, field, &row);
4216
 
  }
4217
 
  else
4218
 
  {
4219
 
    if (my_bind->is_null)
4220
 
      *my_bind->is_null= 1;
4221
 
  }
4222
 
  DBUG_RETURN(0);
4223
 
}
4224
 
 
4225
 
 
4226
 
/*
4227
1772
  Read all rows of data from server  (binary format)
4228
1773
*/
4229
1774
 
4281
1826
  DBUG_RETURN(1);
4282
1827
}
4283
1828
 
4284
 
 
4285
 
/*
4286
 
  Update meta data for statement
4287
 
 
4288
 
  SYNOPSIS
4289
 
    stmt_update_metadata()
4290
 
    stmt                        Statement handler
4291
 
    row                         Binary data
4292
 
 
4293
 
  NOTES
4294
 
    Only updates MYSQL_FIELD->max_length for strings
4295
 
*/
4296
 
 
4297
 
static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data)
4298
 
{
4299
 
  MYSQL_BIND  *my_bind, *end;
4300
 
  MYSQL_FIELD *field;
4301
 
  uchar *null_ptr, bit;
4302
 
  uchar *row= (uchar*) data->data;
4303
 
#ifndef DBUG_OFF
4304
 
  uchar *row_end= row + data->length;
4305
 
#endif
4306
 
 
4307
 
  null_ptr= row;
4308
 
  row+= (stmt->field_count+9)/8;                /* skip null bits */
4309
 
  bit= 4;                                       /* first 2 bits are reserved */
4310
 
 
4311
 
  /* Go through all fields and calculate metadata */
4312
 
  for (my_bind= stmt->bind, end= my_bind + stmt->field_count, field= stmt->fields ;
4313
 
       my_bind < end ;
4314
 
       my_bind++, field++)
4315
 
  {
4316
 
    if (!(*null_ptr & bit))
4317
 
      (*my_bind->skip_result)(my_bind, field, &row);
4318
 
    DBUG_ASSERT(row <= row_end);
4319
 
    if (!((bit<<=1) & 255))
4320
 
    {
4321
 
      bit= 1;                                   /* To next uchar */
4322
 
      null_ptr++;
4323
 
    }
4324
 
  }
4325
 
}
4326
 
 
4327
 
 
4328
 
/*
4329
 
  Store or buffer the binary results to stmt
4330
 
*/
4331
 
 
4332
 
int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
4333
 
{
4334
 
  MYSQL *mysql= stmt->mysql;
4335
 
  MYSQL_DATA *result= &stmt->result;
4336
 
  DBUG_ENTER("mysql_stmt_store_result");
4337
 
 
4338
 
  if (!mysql)
4339
 
  {
4340
 
    /* mysql can be reset in mysql_close called from mysql_reconnect */
4341
 
    set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
4342
 
    DBUG_RETURN(1);
4343
 
  }
4344
 
 
4345
 
  if (!stmt->field_count)
4346
 
    DBUG_RETURN(0);
4347
 
 
4348
 
  if ((int) stmt->state < (int) MYSQL_STMT_EXECUTE_DONE)
4349
 
  {
4350
 
    set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
4351
 
    DBUG_RETURN(1);
4352
 
  }
4353
 
 
4354
 
  if (mysql->status == MYSQL_STATUS_READY &&
4355
 
      stmt->server_status & SERVER_STATUS_CURSOR_EXISTS)
4356
 
  {
4357
 
    /*
4358
 
      Server side cursor exist, tell server to start sending the rows
4359
 
    */
4360
 
    NET *net= &mysql->net;
4361
 
    uchar buff[4 /* statement id */ +
4362
 
               4 /* number of rows to fetch */];
4363
 
 
4364
 
    /* Send row request to the server */
4365
 
    int4store(buff, stmt->stmt_id);
4366
 
    int4store(buff + 4, (int)~0); /* number of rows to fetch */
4367
 
    if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff),
4368
 
                             (uchar*) 0, 0, 1, stmt))
4369
 
    {
4370
 
      set_stmt_errmsg(stmt, net);
4371
 
      DBUG_RETURN(1);
4372
 
    }
4373
 
  }
4374
 
  else if (mysql->status != MYSQL_STATUS_GET_RESULT)
4375
 
  {
4376
 
    set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate, NULL);
4377
 
    DBUG_RETURN(1);
4378
 
  }
4379
 
 
4380
 
  if (stmt->update_max_length && !stmt->bind_result_done)
4381
 
  {
4382
 
    /*
4383
 
      We must initalize the bind structure to be able to calculate
4384
 
      max_length
4385
 
    */
4386
 
    MYSQL_BIND  *my_bind, *end;
4387
 
    MYSQL_FIELD *field;
4388
 
    bzero((char*) stmt->bind, sizeof(*stmt->bind)* stmt->field_count);
4389
 
 
4390
 
    for (my_bind= stmt->bind, end= my_bind + stmt->field_count,
4391
 
           field= stmt->fields;
4392
 
         my_bind < end ;
4393
 
         my_bind++, field++)
4394
 
    {
4395
 
      my_bind->buffer_type= MYSQL_TYPE_NULL;
4396
 
      my_bind->buffer_length=1;
4397
 
    }
4398
 
 
4399
 
    if (mysql_stmt_bind_result(stmt, stmt->bind))
4400
 
      DBUG_RETURN(1);
4401
 
    stmt->bind_result_done= 0;                  /* No normal bind done */
4402
 
  }
4403
 
 
4404
 
  if ((*mysql->methods->read_binary_rows)(stmt))
4405
 
  {
4406
 
    free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
4407
 
    result->data= NULL;
4408
 
    result->rows= 0;
4409
 
    mysql->status= MYSQL_STATUS_READY;
4410
 
    DBUG_RETURN(1);
4411
 
  }
4412
 
 
4413
 
  /* Assert that if there was a cursor, all rows have been fetched */
4414
 
  DBUG_ASSERT(mysql->status != MYSQL_STATUS_READY ||
4415
 
              (mysql->server_status & SERVER_STATUS_LAST_ROW_SENT));
4416
 
 
4417
 
  if (stmt->update_max_length)
4418
 
  {
4419
 
    MYSQL_ROWS *cur= result->data;
4420
 
    for(; cur; cur=cur->next)
4421
 
      stmt_update_metadata(stmt, cur);
4422
 
  }
4423
 
 
4424
 
  stmt->data_cursor= result->data;
4425
 
  mysql->affected_rows= stmt->affected_rows= result->rows;
4426
 
  stmt->read_row_func= stmt_read_row_buffered;
4427
 
  mysql->unbuffered_fetch_owner= 0;             /* set in stmt_execute */
4428
 
  mysql->status= MYSQL_STATUS_READY;            /* server is ready */
4429
 
  DBUG_RETURN(0); /* Data buffered, must be fetched with mysql_stmt_fetch() */
4430
 
}
4431
 
 
4432
 
 
4433
 
/*
4434
 
  Seek to desired row in the statement result set
4435
 
*/
4436
 
 
4437
 
MYSQL_ROW_OFFSET STDCALL
4438
 
mysql_stmt_row_seek(MYSQL_STMT *stmt, MYSQL_ROW_OFFSET row)
4439
 
{
4440
 
  MYSQL_ROW_OFFSET offset= stmt->data_cursor;
4441
 
  DBUG_ENTER("mysql_stmt_row_seek");
4442
 
 
4443
 
  stmt->data_cursor= row;
4444
 
  DBUG_RETURN(offset);
4445
 
}
4446
 
 
4447
 
 
4448
 
/*
4449
 
  Return the current statement row cursor position
4450
 
*/
4451
 
 
4452
 
MYSQL_ROW_OFFSET STDCALL
4453
 
mysql_stmt_row_tell(MYSQL_STMT *stmt)
4454
 
{
4455
 
  DBUG_ENTER("mysql_stmt_row_tell");
4456
 
 
4457
 
  DBUG_RETURN(stmt->data_cursor);
4458
 
}
4459
 
 
4460
 
 
4461
 
/*
4462
 
  Move the stmt result set data cursor to specified row
4463
 
*/
4464
 
 
4465
 
void STDCALL
4466
 
mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row)
4467
 
{
4468
 
  MYSQL_ROWS *tmp= stmt->result.data;
4469
 
  DBUG_ENTER("mysql_stmt_data_seek");
4470
 
  DBUG_PRINT("enter",("row id to seek: %ld",(long) row));
4471
 
 
4472
 
  for (; tmp && row; --row, tmp= tmp->next)
4473
 
    ;
4474
 
  stmt->data_cursor= tmp;
4475
 
  if (!row && tmp)
4476
 
  {
4477
 
       /*  Rewind the counter */
4478
 
    stmt->read_row_func= stmt_read_row_buffered;
4479
 
    stmt->state= MYSQL_STMT_EXECUTE_DONE;
4480
 
  }
4481
 
  DBUG_VOID_RETURN;
4482
 
}
4483
 
 
4484
 
 
4485
 
/*
4486
 
  Return total rows the current statement result set
4487
 
*/
4488
 
 
4489
 
my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt)
4490
 
{
4491
 
  DBUG_ENTER("mysql_stmt_num_rows");
4492
 
 
4493
 
  DBUG_RETURN(stmt->result.rows);
4494
 
}
4495
 
 
4496
 
 
4497
 
/*
4498
 
  Free the client side memory buffers, reset long data state
4499
 
  on client if necessary, and reset the server side statement if
4500
 
  this has been requested.
4501
 
*/
4502
 
 
4503
 
static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
4504
 
{
4505
 
  /* If statement hasn't been prepared there is nothing to reset */
4506
 
  if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
4507
 
  {
4508
 
    MYSQL *mysql= stmt->mysql;
4509
 
    MYSQL_DATA *result= &stmt->result;
4510
 
 
4511
 
    /*
4512
 
      Reset stored result set if so was requested or it's a part
4513
 
      of cursor fetch.
4514
 
    */
4515
 
    if (flags & RESET_STORE_RESULT)
4516
 
    {
4517
 
      /* Result buffered */
4518
 
      free_root(&result->alloc, MYF(MY_KEEP_PREALLOC));
4519
 
      result->data= NULL;
4520
 
      result->rows= 0;
4521
 
      stmt->data_cursor= NULL;
4522
 
    }
4523
 
    if (flags & RESET_LONG_DATA)
4524
 
    {
4525
 
      MYSQL_BIND *param= stmt->params, *param_end= param + stmt->param_count;
4526
 
      /* Clear long_data_used flags */
4527
 
      for (; param < param_end; param++)
4528
 
        param->long_data_used= 0;
4529
 
    }
4530
 
    stmt->read_row_func= stmt_read_row_no_result_set;
4531
 
    if (mysql)
4532
 
    {
4533
 
      if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE)
4534
 
      {
4535
 
        if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
4536
 
          mysql->unbuffered_fetch_owner= 0;
4537
 
        if (stmt->field_count && mysql->status != MYSQL_STATUS_READY)
4538
 
        {
4539
 
          /* There is a result set and it belongs to this statement */
4540
 
          (*mysql->methods->flush_use_result)(mysql);
4541
 
          if (mysql->unbuffered_fetch_owner)
4542
 
            *mysql->unbuffered_fetch_owner= TRUE;
4543
 
          mysql->status= MYSQL_STATUS_READY;
4544
 
        }
4545
 
      }
4546
 
      if (flags & RESET_SERVER_SIDE)
4547
 
      {
4548
 
        /*
4549
 
          Reset the server side statement and close the server side
4550
 
          cursor if it exists.
4551
 
        */
4552
 
        uchar buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */
4553
 
        int4store(buff, stmt->stmt_id);
4554
 
        if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff,
4555
 
                                                sizeof(buff), 0, 0, 0, stmt))
4556
 
        {
4557
 
          set_stmt_errmsg(stmt, &mysql->net);
4558
 
          stmt->state= MYSQL_STMT_INIT_DONE;
4559
 
          return 1;
4560
 
        }
4561
 
        stmt_clear_error(stmt);
4562
 
      }
4563
 
    }
4564
 
    stmt->state= MYSQL_STMT_PREPARE_DONE;
4565
 
  }
4566
 
  return 0;
4567
 
}
4568
 
 
4569
 
my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt)
4570
 
{
4571
 
  DBUG_ENTER("mysql_stmt_free_result");
4572
 
 
4573
 
  /* Free the client side and close the server side cursor if there is one */
4574
 
  DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA | RESET_STORE_RESULT));
4575
 
}
4576
 
 
4577
 
/********************************************************************
4578
 
 statement error handling and close
4579
 
*********************************************************************/
4580
 
 
4581
 
/*
4582
 
  Close the statement handle by freeing all alloced resources
4583
 
 
4584
 
  SYNOPSIS
4585
 
    mysql_stmt_close()
4586
 
    stmt               Statement handle
4587
 
 
4588
 
  RETURN VALUES
4589
 
    0   ok
4590
 
    1   error
4591
 
*/
4592
 
 
4593
 
my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
4594
 
{
4595
 
  MYSQL *mysql= stmt->mysql;
4596
 
  int rc= 0;
4597
 
  DBUG_ENTER("mysql_stmt_close");
4598
 
 
4599
 
  free_root(&stmt->result.alloc, MYF(0));
4600
 
  free_root(&stmt->mem_root, MYF(0));
4601
 
 
4602
 
  if (mysql)
4603
 
  {
4604
 
    mysql->stmts= list_delete(mysql->stmts, &stmt->list);
4605
 
    /*
4606
 
      Clear NET error state: if the following commands come through
4607
 
      successfully, connection will still be usable for other commands.
4608
 
    */
4609
 
    net_clear_error(&mysql->net);
4610
 
    if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
4611
 
    {
4612
 
      uchar buff[MYSQL_STMT_HEADER];             /* 4 bytes - stmt id */
4613
 
 
4614
 
      if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
4615
 
        mysql->unbuffered_fetch_owner= 0;
4616
 
      if (mysql->status != MYSQL_STATUS_READY)
4617
 
      {
4618
 
        /*
4619
 
          Flush result set of the connection. If it does not belong
4620
 
          to this statement, set a warning.
4621
 
        */
4622
 
        (*mysql->methods->flush_use_result)(mysql);
4623
 
        if (mysql->unbuffered_fetch_owner)
4624
 
          *mysql->unbuffered_fetch_owner= TRUE;
4625
 
        mysql->status= MYSQL_STATUS_READY;
4626
 
      }
4627
 
      int4store(buff, stmt->stmt_id);
4628
 
      if ((rc= stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt)))
4629
 
      {
4630
 
        set_stmt_errmsg(stmt, &mysql->net);
4631
 
      }
4632
 
    }
4633
 
  }
4634
 
 
4635
 
  my_free((uchar*) stmt, MYF(MY_WME));
4636
 
 
4637
 
  DBUG_RETURN(test(rc));
4638
 
}
4639
 
 
4640
 
/*
4641
 
  Reset the statement buffers in server
4642
 
*/
4643
 
 
4644
 
my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt)
4645
 
{
4646
 
  DBUG_ENTER("mysql_stmt_reset");
4647
 
  DBUG_ASSERT(stmt != 0);
4648
 
  if (!stmt->mysql)
4649
 
  {
4650
 
    /* mysql can be reset in mysql_close called from mysql_reconnect */
4651
 
    set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
4652
 
    DBUG_RETURN(1);
4653
 
  }
4654
 
  /* Reset the client and server sides of the prepared statement */
4655
 
  DBUG_RETURN(reset_stmt_handle(stmt, RESET_SERVER_SIDE | RESET_LONG_DATA));
4656
 
}
4657
 
 
4658
 
/*
4659
 
  Return statement error code
4660
 
*/
4661
 
 
4662
 
uint STDCALL mysql_stmt_errno(MYSQL_STMT * stmt)
4663
 
{
4664
 
  DBUG_ENTER("mysql_stmt_errno");
4665
 
  DBUG_RETURN(stmt->last_errno);
4666
 
}
4667
 
 
4668
 
const char *STDCALL mysql_stmt_sqlstate(MYSQL_STMT * stmt)
4669
 
{
4670
 
  DBUG_ENTER("mysql_stmt_sqlstate");
4671
 
  DBUG_RETURN(stmt->sqlstate);
4672
 
}
4673
 
 
4674
 
/*
4675
 
  Return statement error message
4676
 
*/
4677
 
 
4678
 
const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt)
4679
 
{
4680
 
  DBUG_ENTER("mysql_stmt_error");
4681
 
  DBUG_RETURN(stmt->last_error);
4682
 
}
4683
 
 
4684
 
 
4685
1829
/********************************************************************
4686
1830
 Transactional APIs
4687
1831
*********************************************************************/