~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to libmysql/libmysql.c

  • Committer: Brian Aker
  • Date: 2008-07-02 15:58:43 UTC
  • mfrom: (37.1.1 remove_unittest)
  • Revision ID: brian@tangent.org-20080702155843-b30y15sirrcb874u
Removing unittest (merge from patg's tree)

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
159
162
      mysql_unix_port = (char*) MYSQL_UNIX_ADDR;
 
163
#endif
160
164
      if ((env = getenv("MYSQL_UNIX_PORT")))
161
165
        mysql_unix_port = env;
162
166
    }
163
167
    mysql_debug(NullS);
164
 
#if defined(SIGPIPE)
 
168
#if defined(SIGPIPE) && !defined(__WIN__) && !defined(__NETWARE__)
165
169
    (void) signal(SIGPIPE, SIG_IGN);
166
170
#endif
 
171
#ifdef EMBEDDED_LIBRARY
 
172
    if (argc > -1)
 
173
       result= init_embedded_server(argc, argv, groups);
 
174
#endif
167
175
  }
168
176
#ifdef THREAD
169
177
  else
190
198
  if (!mysql_client_init)
191
199
    return;
192
200
 
 
201
#ifdef EMBEDDED_LIBRARY
 
202
  end_embedded_server();
 
203
#endif
193
204
  finish_client_errs();
194
205
  vio_end();
195
206
 
437
448
 
438
449
  rc= (*mysql->methods->read_change_user_result)(mysql, buff, passwd);
439
450
 
 
451
  /*
 
452
    The server will close all statements no matter was the attempt
 
453
    to change user successful or not.
 
454
  */
 
455
  mysql_detach_stmt_list(&mysql->stmts, "mysql_change_user");
440
456
  if (rc == 0)
441
457
  {
442
458
    /* Free old connect information */
1265
1281
 'emb_' reside in libmysqld/lib_sql.cc.
1266
1282
*********************************************************************/
1267
1283
 
 
1284
/******************* Declarations ***********************************/
 
1285
 
 
1286
/* Default number of rows fetched per one COM_STMT_FETCH command. */
 
1287
 
 
1288
#define DEFAULT_PREFETCH_ROWS (ulong) 1
 
1289
 
 
1290
/*
 
1291
  These functions are called by function pointer MYSQL_STMT::read_row_func.
 
1292
  Each function corresponds to one of the read methods:
 
1293
  - mysql_stmt_fetch without prior mysql_stmt_store_result,
 
1294
  - mysql_stmt_fetch when result is stored,
 
1295
  - mysql_stmt_fetch when there are no rows (always returns MYSQL_NO_DATA)
 
1296
*/
 
1297
 
 
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
/*
 
1305
  This function is used in mysql_stmt_store_result if
 
1306
  STMT_ATTR_UPDATE_MAX_LENGTH attribute is set.
 
1307
*/
 
1308
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
 
 
1311
/* Auxilary function used to reset statement handle. */
 
1312
 
 
1313
#define RESET_SERVER_SIDE 1
 
1314
#define RESET_LONG_DATA 2
 
1315
#define RESET_STORE_RESULT 4
 
1316
 
 
1317
static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags);
 
1318
 
 
1319
/*
 
1320
  Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME
 
1321
  values stored in network buffer.
 
1322
*/
 
1323
 
 
1324
/* 1 (length) + 2 (year) + 1 (month) + 1 (day) */
 
1325
#define MAX_DATE_REP_LENGTH 5
 
1326
 
 
1327
/*
 
1328
  1 (length) + 1 (is negative) + 4 (day count) + 1 (hour)
 
1329
  + 1 (minute) + 1 (seconds) + 4 (microseconds)
 
1330
*/
 
1331
#define MAX_TIME_REP_LENGTH 13
 
1332
 
 
1333
/*
 
1334
  1 (length) + 2 (year) + 1 (month) + 1 (day) +
 
1335
  1 (hour) + 1 (minute) + 1 (second) + 4 (microseconds)
 
1336
*/
 
1337
#define MAX_DATETIME_REP_LENGTH 12
 
1338
 
 
1339
#define MAX_DOUBLE_STRING_REP_LENGTH 331
 
1340
 
 
1341
/* A macro to check truncation errors */
 
1342
 
 
1343
#define IS_TRUNCATED(value, is_unsigned, min, max, umax) \
 
1344
        ((is_unsigned) ? (((value) > (umax) || (value) < 0) ? 1 : 0) : \
 
1345
                         (((value) > (max)  || (value) < (min)) ? 1 : 0))
 
1346
 
 
1347
#define BIND_RESULT_DONE 1
 
1348
/*
 
1349
  We report truncations only if at least one of MYSQL_BIND::error
 
1350
  pointers is set. In this case stmt->bind_result_done |-ed with
 
1351
  this flag.
 
1352
*/
 
1353
#define REPORT_DATA_TRUNCATION 2
 
1354
 
 
1355
/**************** Misc utility functions ****************************/
 
1356
 
 
1357
/*
 
1358
  Reallocate the NET package to have at least length bytes available.
 
1359
 
 
1360
  SYNPOSIS
 
1361
    my_realloc_str()
 
1362
    net                 The NET structure to modify.
 
1363
    length              Ensure that net->buff has space for at least
 
1364
                        this number of bytes.
 
1365
 
 
1366
  RETURN VALUES
 
1367
    0   Success.
 
1368
    1   Error, i.e. out of memory or requested packet size is bigger
 
1369
        than max_allowed_packet. The error code is stored in net->last_errno.
 
1370
*/
 
1371
 
 
1372
static my_bool my_realloc_str(NET *net, ulong length)
 
1373
{
 
1374
  ulong buf_length= (ulong) (net->write_pos - net->buff);
 
1375
  my_bool res=0;
 
1376
  DBUG_ENTER("my_realloc_str");
 
1377
  if (buf_length + length > net->max_packet)
 
1378
  {
 
1379
    res= net_realloc(net, buf_length + length);
 
1380
    if (res)
 
1381
    {
 
1382
      strmov(net->sqlstate, unknown_sqlstate);
 
1383
      strmov(net->last_error, ER(net->last_errno));
 
1384
    }
 
1385
    net->write_pos= net->buff+ buf_length;
 
1386
  }
 
1387
  DBUG_RETURN(res);
 
1388
}
 
1389
 
 
1390
 
 
1391
static void stmt_clear_error(MYSQL_STMT *stmt)
 
1392
{
 
1393
  if (stmt->last_errno)
 
1394
  {
 
1395
    stmt->last_errno= 0;
 
1396
    stmt->last_error[0]= '\0';
 
1397
    strmov(stmt->sqlstate, not_error_sqlstate);
 
1398
  }
 
1399
}
 
1400
 
 
1401
/**
 
1402
  Set statement error code, sqlstate, and error message
 
1403
  from given errcode and sqlstate.
 
1404
*/
 
1405
 
 
1406
void set_stmt_error(MYSQL_STMT * stmt, int errcode,
 
1407
                    const char *sqlstate, const char *err)
 
1408
{
 
1409
  DBUG_ENTER("set_stmt_error");
 
1410
  DBUG_PRINT("enter", ("error: %d '%s'", errcode, ER(errcode)));
 
1411
  DBUG_ASSERT(stmt != 0);
 
1412
 
 
1413
  if (err == 0)
 
1414
    err= ER(errcode);
 
1415
 
 
1416
  stmt->last_errno= errcode;
 
1417
  strmov(stmt->last_error, ER(errcode));
 
1418
  strmov(stmt->sqlstate, sqlstate);
 
1419
 
 
1420
  DBUG_VOID_RETURN;
 
1421
}
 
1422
 
 
1423
 
 
1424
/**
 
1425
  Set statement error code, sqlstate, and error message from NET.
 
1426
 
 
1427
  @param stmt  a statement handle. Copy the error here.
 
1428
  @param net   mysql->net. Source of the error.
 
1429
*/
 
1430
 
 
1431
void set_stmt_errmsg(MYSQL_STMT *stmt, NET *net)
 
1432
{
 
1433
  DBUG_ENTER("set_stmt_errmsg");
 
1434
  DBUG_PRINT("enter", ("error: %d/%s '%s'",
 
1435
                       net->last_errno,
 
1436
                       net->sqlstate,
 
1437
                       net->last_error));
 
1438
  DBUG_ASSERT(stmt != 0);
 
1439
 
 
1440
  stmt->last_errno= net->last_errno;
 
1441
  if (net->last_error && net->last_error[0])
 
1442
    strmov(stmt->last_error, net->last_error);
 
1443
  strmov(stmt->sqlstate, net->sqlstate);
 
1444
 
 
1445
  DBUG_VOID_RETURN;
 
1446
}
 
1447
 
 
1448
/*
 
1449
  Read and unpack server reply to COM_STMT_PREPARE command (sent from
 
1450
  mysql_stmt_prepare).
 
1451
 
 
1452
  SYNOPSIS
 
1453
    cli_read_prepare_result()
 
1454
    mysql   connection handle
 
1455
    stmt    statement handle
 
1456
 
 
1457
  RETURN VALUES
 
1458
    0   ok
 
1459
    1   error
 
1460
*/
 
1461
 
 
1462
my_bool cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
 
1463
{
 
1464
  uchar *pos;
 
1465
  uint field_count, param_count;
 
1466
  ulong packet_length;
 
1467
  MYSQL_DATA *fields_data;
 
1468
  DBUG_ENTER("cli_read_prepare_result");
 
1469
 
 
1470
  if ((packet_length= cli_safe_read(mysql)) == packet_error)
 
1471
    DBUG_RETURN(1);
 
1472
  mysql->warning_count= 0;
 
1473
 
 
1474
  pos= (uchar*) mysql->net.read_pos;
 
1475
  stmt->stmt_id= uint4korr(pos+1); pos+= 5;
 
1476
  /* Number of columns in result set */
 
1477
  field_count=   uint2korr(pos);   pos+= 2;
 
1478
  /* Number of placeholders in the statement */
 
1479
  param_count=   uint2korr(pos);   pos+= 2;
 
1480
  if (packet_length >= 12)
 
1481
    mysql->warning_count= uint2korr(pos+1);
 
1482
 
 
1483
  if (param_count != 0)
 
1484
  {
 
1485
    MYSQL_DATA *param_data;
 
1486
 
 
1487
    /* skip parameters data: we don't support it yet */
 
1488
    if (!(param_data= (*mysql->methods->read_rows)(mysql, (MYSQL_FIELD*)0, 7)))
 
1489
      DBUG_RETURN(1);
 
1490
    free_rows(param_data);
 
1491
  }
 
1492
 
 
1493
  if (field_count != 0)
 
1494
  {
 
1495
    if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
 
1496
      mysql->server_status|= SERVER_STATUS_IN_TRANS;
 
1497
 
 
1498
    if (!(fields_data= (*mysql->methods->read_rows)(mysql,(MYSQL_FIELD*)0,7)))
 
1499
      DBUG_RETURN(1);
 
1500
    if (!(stmt->fields= unpack_fields(fields_data,&stmt->mem_root,
 
1501
                                      field_count,0,
 
1502
                                      mysql->server_capabilities)))
 
1503
      DBUG_RETURN(1);
 
1504
  }
 
1505
  stmt->field_count=  field_count;
 
1506
  stmt->param_count=  (ulong) param_count;
 
1507
  DBUG_PRINT("exit",("field_count: %u  param_count: %u  warning_count: %u",
 
1508
                     field_count, param_count, (uint) mysql->warning_count));
 
1509
 
 
1510
  DBUG_RETURN(0);
 
1511
}
 
1512
 
 
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
static void net_store_datetime(NET *net, MYSQL_TIME *tm)
 
1951
{
 
1952
  char buff[MAX_DATETIME_REP_LENGTH], *pos;
 
1953
  uint length;
 
1954
 
 
1955
  pos= buff+1;
 
1956
 
 
1957
  int2store(pos, tm->year);
 
1958
  pos[2]= (uchar) tm->month;
 
1959
  pos[3]= (uchar) tm->day;
 
1960
  pos[4]= (uchar) tm->hour;
 
1961
  pos[5]= (uchar) tm->minute;
 
1962
  pos[6]= (uchar) tm->second;
 
1963
  int4store(pos+7, tm->second_part);
 
1964
  if (tm->second_part)
 
1965
    length= 11;
 
1966
  else if (tm->hour || tm->minute || tm->second)
 
1967
    length= 7;
 
1968
  else if (tm->year || tm->month || tm->day)
 
1969
    length= 4;
 
1970
  else
 
1971
    length= 0;
 
1972
  buff[0]= (char) length++;
 
1973
  memcpy((char *)net->write_pos, buff, length);
 
1974
  net->write_pos+= length;
 
1975
}
 
1976
 
 
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
/*
 
2192
  Read one row from network: unbuffered non-cursor fetch.
 
2193
  If last row was read, or error occured, erase this statement
 
2194
  from record pointing to object unbuffered fetch is performed from.
 
2195
 
 
2196
  SYNOPSIS
 
2197
    stmt_read_row_unbuffered()
 
2198
    stmt  statement handle
 
2199
    row   pointer to write pointer to row data;
 
2200
 
 
2201
  RETURN VALUE
 
2202
    0           - success; *row contains valid address of a row;
 
2203
                  row data is stored in network buffer
 
2204
    1           - error; error code is written to
 
2205
                  stmt->last_{errno,error}; *row is not changed
 
2206
  MYSQL_NO_DATA - end of file was read from network;
 
2207
                  *row is set to NULL
 
2208
*/
 
2209
 
 
2210
static int stmt_read_row_unbuffered(MYSQL_STMT *stmt, unsigned char **row)
 
2211
{
 
2212
  int rc= 1;
 
2213
  MYSQL *mysql= stmt->mysql;
 
2214
  /*
 
2215
    This function won't be called if stmt->field_count is zero
 
2216
    or execution wasn't done: this is ensured by mysql_stmt_execute.
 
2217
  */
 
2218
  if (!mysql)
 
2219
  {
 
2220
    set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
 
2221
    return 1;
 
2222
  }
 
2223
  if (mysql->status != MYSQL_STATUS_GET_RESULT)
 
2224
  {
 
2225
    set_stmt_error(stmt, stmt->unbuffered_fetch_cancelled ?
 
2226
                   CR_FETCH_CANCELED : CR_COMMANDS_OUT_OF_SYNC,
 
2227
                   unknown_sqlstate, NULL);
 
2228
    goto error;
 
2229
  }
 
2230
  if ((*mysql->methods->unbuffered_fetch)(mysql, (char**) row))
 
2231
  {
 
2232
    set_stmt_errmsg(stmt, &mysql->net);
 
2233
    /*
 
2234
      If there was an error, there are no more pending rows:
 
2235
      reset statement status to not hang up in following
 
2236
      mysql_stmt_close (it will try to flush result set before
 
2237
      closing the statement).
 
2238
    */
 
2239
    mysql->status= MYSQL_STATUS_READY;
 
2240
    goto error;
 
2241
  }
 
2242
  if (!*row)
 
2243
  {
 
2244
    mysql->status= MYSQL_STATUS_READY;
 
2245
    rc= MYSQL_NO_DATA;
 
2246
    goto error;
 
2247
  }
 
2248
  return 0;
 
2249
error:
 
2250
  if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled)
 
2251
    mysql->unbuffered_fetch_owner= 0;
 
2252
  return rc;
 
2253
}
 
2254
 
 
2255
 
 
2256
/*
 
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
  Default read row function to not SIGSEGV in client in
 
2310
  case of wrong sequence of API calls.
 
2311
*/
 
2312
 
 
2313
static int
 
2314
stmt_read_row_no_data(MYSQL_STMT *stmt  __attribute__((unused)),
 
2315
                      unsigned char **row  __attribute__((unused)))
 
2316
{
 
2317
  return MYSQL_NO_DATA;
 
2318
}
 
2319
 
 
2320
static int
 
2321
stmt_read_row_no_result_set(MYSQL_STMT *stmt  __attribute__((unused)),
 
2322
                      unsigned char **row  __attribute__((unused)))
 
2323
{
 
2324
  set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate, NULL);
 
2325
  return 1;
 
2326
}
 
2327
 
 
2328
 
 
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
 
1268
2575
 
1269
2576
static my_bool int_is_null_true= 1;             /* Used for MYSQL_TYPE_NULL */
1270
2577
static my_bool int_is_null_false= 0;
1271
2578
 
 
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
 
1272
2968
/********************************************************************
1273
2969
 Fetch and conversion of result set rows (binary protocol).
1274
2970
*********************************************************************/
1373
3069
 
1374
3070
 
1375
3071
/*
 
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
/*
1376
3775
  Check that two field types are binary compatible i. e.
1377
3776
  have equal representation in the binary protocol and
1378
3777
  require client-side buffers of the same type.
1420
3819
}
1421
3820
 
1422
3821
 
 
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
 
1423
4131
int cli_unbuffered_fetch(MYSQL *mysql, char **row)
1424
4132
{
1425
4133
  if (packet_error == cli_safe_read(mysql))
1430
4138
  return 0;
1431
4139
}
1432
4140
 
 
4141
 
 
4142
/*
 
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
  Read all rows of data from server  (binary format)
 
4228
*/
 
4229
 
 
4230
int cli_read_binary_rows(MYSQL_STMT *stmt)
 
4231
{
 
4232
  ulong      pkt_len;
 
4233
  uchar      *cp;
 
4234
  MYSQL      *mysql= stmt->mysql;
 
4235
  MYSQL_DATA *result= &stmt->result;
 
4236
  MYSQL_ROWS *cur, **prev_ptr= &result->data;
 
4237
  NET        *net;
 
4238
 
 
4239
  DBUG_ENTER("cli_read_binary_rows");
 
4240
 
 
4241
  if (!mysql)
 
4242
  {
 
4243
    set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate, NULL);
 
4244
    DBUG_RETURN(1);
 
4245
  }
 
4246
 
 
4247
  net = &mysql->net;
 
4248
 
 
4249
  while ((pkt_len= cli_safe_read(mysql)) != packet_error)
 
4250
  {
 
4251
    cp= net->read_pos;
 
4252
    if (cp[0] != 254 || pkt_len >= 8)
 
4253
    {
 
4254
      if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc,
 
4255
                                          sizeof(MYSQL_ROWS) + pkt_len - 1)))
 
4256
      {
 
4257
        set_stmt_error(stmt, CR_OUT_OF_MEMORY, unknown_sqlstate, NULL);
 
4258
        goto err;
 
4259
      }
 
4260
      cur->data= (MYSQL_ROW) (cur+1);
 
4261
      *prev_ptr= cur;
 
4262
      prev_ptr= &cur->next;
 
4263
      memcpy((char *) cur->data, (char *) cp+1, pkt_len-1);
 
4264
      cur->length= pkt_len;             /* To allow us to do sanity checks */
 
4265
      result->rows++;
 
4266
    }
 
4267
    else
 
4268
    {
 
4269
      /* end of data */
 
4270
      *prev_ptr= 0;
 
4271
      mysql->warning_count= uint2korr(cp+1);
 
4272
      mysql->server_status= uint2korr(cp+3);
 
4273
      DBUG_PRINT("info",("status: %u  warning_count: %u",
 
4274
                         mysql->server_status, mysql->warning_count));
 
4275
      DBUG_RETURN(0);
 
4276
    }
 
4277
  }
 
4278
  set_stmt_errmsg(stmt, net);
 
4279
 
 
4280
err:
 
4281
  DBUG_RETURN(1);
 
4282
}
 
4283
 
 
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
 
1433
4685
/********************************************************************
1434
4686
 Transactional APIs
1435
4687
*********************************************************************/