~ubuntu-branches/ubuntu/karmic/edbrowse/karmic-security

« back to all changes in this revision

Viewing changes to src/dbinfx.c

  • Committer: Bazaar Package Importer
  • Author(s): Kapil Hari Paranjape
  • Date: 2009-03-01 16:55:12 UTC
  • mfrom: (1.1.5 upstream) (3.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090301165512-97yhte20cy3c4q2w
Tags: 3.4.1-1
* New upstream version (3.4.1).
* debian/rules:
  - add "touch build-stamp" to build-stamp target.
  - modify clean target to use clean target in src/makefile.
  - remove debian/edbrowse.1 in clean target.
  - added "-lcurl" to linker flags.
* debian/control:
  - added libcurl4-openssl-dev to Build-Depends
  - Standards Version 3.8.0. No changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1069
1069
static bool badtrans;
1070
1070
 
1071
1071
/* Through globals, make error info available to the application. */
1072
 
int rv_lastStatus, rv_vendorStatus, rv_stmtOffset;
 
1072
int rv_lastStatus, rv_stmtOffset;
 
1073
long rv_vendorStatus;
1073
1074
char *rv_badToken;
1074
1075
 
1075
1076
static void debugStatement(void)
1102
1103
        exclist = list;
1103
1104
} /* sql_exception */
1104
1105
 
1105
 
/* text descriptions corresponding to our generic SQL error codes */
1106
 
static char *sqlErrorList[] = {0,
1107
 
        "miscelaneous SQL error",
1108
 
        "syntax error in SQL statement",
1109
 
        "filename cannot be used by SQL",
1110
 
        "cannot convert/compare the columns/constants in the SQL statement",
1111
 
        "bad string subscripting",
1112
 
        "bad use of the rowid construct",
1113
 
        "bad use of a blob column",
1114
 
        "bad use of aggregate operators or columns",
1115
 
        "bad use of a view",
1116
 
        "bad use of a serial column",
1117
 
        "bad use of a temp table",
1118
 
        "operation cannot cross databases",
1119
 
        "database is fucked up",
1120
 
        "query interrupted by user",
1121
 
        "could not connect to the database",
1122
 
        "database has not yet been selected",
1123
 
        "table not found",
1124
 
        "duplicate table",
1125
 
        "ambiguous table",
1126
 
        "column not found",
1127
 
        "duplicate column",
1128
 
        "ambiguous column",
1129
 
        "index not found",
1130
 
        "duplicate index",
1131
 
        "constraint not found",
1132
 
        "duplicate constraint",
1133
 
        "stored procedure not found",
1134
 
        "duplicate stored procedure",
1135
 
        "synonym not found",
1136
 
        "duplicate synonym",
1137
 
        "table has no primary or unique key",
1138
 
        "duplicate primary or unique key",
1139
 
        "cursor not specified, or cursor is not available",
1140
 
        "duplicate cursor",
1141
 
        "the database lacks the resources needed to complete this query",
1142
 
        "check constrain violated",
1143
 
        "referential integrity violated",
1144
 
        "cannot manage or complete the transaction",
1145
 
        "long transaction, too much log data generated",
1146
 
        "this operation must be run inside a transaction",
1147
 
        "cannot open, read, write, close, or otherwise manage a blob",
1148
 
        "row, table, page, or database is already locked, or cannot be locked",
1149
 
        "inserting null into a not null column",
1150
 
        "no permission to modify the database in this way",
1151
 
        "no current row established",
1152
 
        "many rows were found where one was expected",
1153
 
        "cannot union these select statements together",
1154
 
        "cannot access or write the audit trail",
1155
 
        "could not run SQL or gather data from a remote host",
1156
 
        "where clause is semantically unmanageable",
1157
 
        "deadlock detected",
1158
 
0};
1159
 
 
1160
 
/* map Informix errors to our own exception codes, as defined in c_sql.h. */
1161
 
static struct ERRORMAP {
 
1106
/* map Informix errors to our own exception codes, as defined in dbapi.h. */
 
1107
static const struct ERRORMAP {
1162
1108
        short infcode;
1163
1109
        short excno;
1164
1110
} errormap[] = {
1522
1468
 
1523
1469
static int errTranslate(int code)
1524
1470
{
1525
 
        struct ERRORMAP *e;
 
1471
        const struct ERRORMAP *e;
1526
1472
 
1527
1473
        for(e=errormap; e->infcode; ++e) {
1528
1474
                if(e->infcode == code)
1535
1481
{
1536
1482
short i;
1537
1483
 
1538
 
rv_lastStatus = rv_vendorStatus = 0; /* innocent until proven guilty */
 
1484
/* innocent until proven guilty */
 
1485
rv_lastStatus = 0;
 
1486
rv_vendorStatus = 0;
1539
1487
rv_stmtOffset = 0;
1540
1488
rv_badToken = 0;
1541
1489
if(ENGINE_ERRCODE >= 0) return false; /* no problem */
1542
1490
 
 
1491
        /* log the SQL statement that elicitted the error */
1543
1492
showStatement();
1544
1493
rv_vendorStatus = -ENGINE_ERRCODE;
1545
1494
rv_lastStatus = errTranslate(rv_vendorStatus);
1548
1497
if(!rv_badToken[0]) rv_badToken = 0;
1549
1498
 
1550
1499
/* if the application didn't trap for this exception, blow up! */
1551
 
if(exclist) {
1552
 
for(i=0; exclist[i]; ++i) {
 
1500
if(exclist)
 
1501
for(i=0; exclist[i]; ++i)
1553
1502
if(exclist[i] == rv_lastStatus) {
1554
1503
exclist = 0; /* we've spent that exception */
1555
1504
return true;
1556
1505
}
1557
 
}
1558
 
}
1559
1506
 
 
1507
/* Remember, errorPrint() should not return. */
1560
1508
errorPrint("2SQL error %d, %s", rv_vendorStatus, sqlErrorList[rv_lastStatus]);
1561
1509
return true; /* make the compiler happy */
1562
1510
} /* errorTrap */
1574
1522
struct sqlda *desc;
1575
1523
char rv_type[NUMRETS];
1576
1524
long rownum;
1577
 
short alloc;
1578
1525
short cid; /* cursor ID */
1579
1526
char flag;
1580
1527
char numRets;
1581
 
char **fl; /* array of fetched lines */
1582
1528
} ocurs[NUMCURSORS];
1583
1529
 
1584
1530
/* values for struct OCURS.flag */
1617
1563
return o;
1618
1564
} /* findCursor */
1619
1565
 
 
1566
/* This doesn't close/free anything; it simply puts variables in an initial state. */
1620
1567
/* part of the disconnect() procedure */
1621
1568
static void clearAllCursors(void)
1622
1569
{
1627
1574
                if(o->flag == CURSOR_NONE) continue;
1628
1575
                o->flag = CURSOR_NONE;
1629
1576
o->rownum = 0;
1630
 
                if(o->fl) {
1631
 
                        for(j=0; j<o->alloc; ++j)
1632
 
                                nzFree(o->fl[j]);
1633
 
                        nzFree(o->fl);
1634
 
                        o->fl = 0;
1635
 
                }
1636
1577
        } /* loop over cursors */
1637
1578
 
1638
1579
        translevel = 0;
1649
1590
/*
1650
1591
 * $char *dblocal = (char*)db;
1651
1592
 */
1652
 
#line 637 "dbinfx.ec"
 
1593
#line 578 "dbinfx.ec"
1653
1594
  char *dblocal = (char*)db;
1654
1595
login = pw = 0; /* not used here, so make the compiler happy */
1655
1596
if(isnullstring(dblocal)) {
1664
1605
/*
1665
1606
 * $disconnect current;
1666
1607
 */
1667
 
#line 648 "dbinfx.ec"
 
1608
#line 589 "dbinfx.ec"
1668
1609
  {
1669
 
#line 648 "dbinfx.ec"
 
1610
#line 589 "dbinfx.ec"
1670
1611
  sqli_connect_close(3, (char *)0, 0, 0);
1671
 
#line 648 "dbinfx.ec"
 
1612
#line 589 "dbinfx.ec"
1672
1613
  }
1673
1614
clearAllCursors();
1674
1615
sql_database = 0;
1679
1620
/*
1680
1621
 * $connect to :dblocal;
1681
1622
 */
1682
 
#line 655 "dbinfx.ec"
 
1623
#line 596 "dbinfx.ec"
1683
1624
  {
1684
 
#line 655 "dbinfx.ec"
 
1625
#line 596 "dbinfx.ec"
1685
1626
  sqli_connect_open(ESQLINTVERSION, 0, dblocal, (char *)0, (ifx_conn_t *)0, 0);
1686
 
#line 655 "dbinfx.ec"
 
1627
#line 596 "dbinfx.ec"
1687
1628
  }
1688
1629
if(errorTrap()) return;
1689
1630
sql_database = dblocal;
1694
1635
/*
1695
1636
 * $ set lock mode to wait;
1696
1637
 */
1697
 
#line 662 "dbinfx.ec"
 
1638
#line 603 "dbinfx.ec"
1698
1639
  {
1699
 
#line 662 "dbinfx.ec"
 
1640
#line 603 "dbinfx.ec"
1700
1641
  static const char *sqlcmdtxt[] =
1701
 
#line 662 "dbinfx.ec"
 
1642
#line 603 "dbinfx.ec"
1702
1643
    {
1703
 
#line 662 "dbinfx.ec"
 
1644
#line 603 "dbinfx.ec"
1704
1645
    "set lock mode to wait",
1705
1646
    0
1706
1647
    };
1707
 
#line 662 "dbinfx.ec"
 
1648
#line 603 "dbinfx.ec"
1708
1649
  static ifx_statement_t _SQ0 = {0};
1709
 
#line 662 "dbinfx.ec"
 
1650
#line 603 "dbinfx.ec"
1710
1651
  sqli_stmt(ESQLINTVERSION, &_SQ0, sqlcmdtxt, 0, (ifx_sqlvar_t *)0, (struct value *)0, (ifx_literal_t *)0, (ifx_namelist_t *)0, (ifx_cursor_t *)0, -1, 0, 0);
1711
 
#line 662 "dbinfx.ec"
 
1652
#line 603 "dbinfx.ec"
1712
1653
  }
1713
1654
if(errorTrap()) {
1714
1655
abort:
1718
1659
/*
1719
1660
 * $ set isolation to committed read;
1720
1661
 */
1721
 
#line 668 "dbinfx.ec"
 
1662
#line 609 "dbinfx.ec"
1722
1663
  {
1723
 
#line 668 "dbinfx.ec"
 
1664
#line 609 "dbinfx.ec"
1724
1665
  static const char *sqlcmdtxt[] =
1725
 
#line 668 "dbinfx.ec"
 
1666
#line 609 "dbinfx.ec"
1726
1667
    {
1727
 
#line 668 "dbinfx.ec"
 
1668
#line 609 "dbinfx.ec"
1728
1669
    "set isolation to committed read",
1729
1670
    0
1730
1671
    };
1731
 
#line 668 "dbinfx.ec"
 
1672
#line 609 "dbinfx.ec"
1732
1673
  static ifx_statement_t _SQ0 = {0};
1733
 
#line 668 "dbinfx.ec"
 
1674
#line 609 "dbinfx.ec"
1734
1675
  sqli_stmt(ESQLINTVERSION, &_SQ0, sqlcmdtxt, 0, (ifx_sqlvar_t *)0, (struct value *)0, (ifx_literal_t *)0, (ifx_namelist_t *)0, (ifx_cursor_t *)0, -1, 0, 0);
1735
 
#line 668 "dbinfx.ec"
 
1676
#line 609 "dbinfx.ec"
1736
1677
  }
1737
1678
if(errorTrap()) goto abort;
1738
1679
exclist = 0;
1746
1687
/*
1747
1688
 * $disconnect current;
1748
1689
 */
1749
 
#line 678 "dbinfx.ec"
 
1690
#line 619 "dbinfx.ec"
1750
1691
  {
1751
 
#line 678 "dbinfx.ec"
 
1692
#line 619 "dbinfx.ec"
1752
1693
  sqli_connect_close(3, (char *)0, 0, 0);
1753
 
#line 678 "dbinfx.ec"
 
1694
#line 619 "dbinfx.ec"
1754
1695
  }
1755
1696
clearAllCursors();
1756
1697
sql_database = 0;
1781
1722
{
1782
1723
        rv_lastStatus = 0;
1783
1724
        checkConnect();
1784
 
                stmt_text = "begin work";
1785
 
                debugStatement();
 
1725
stmt_text = 0;
 
1726
 
1786
1727
        /* count the nesting level of transactions. */
1787
1728
        if(!translevel) {
1788
1729
                badtrans = false;
 
1730
                stmt_text = "begin work";
 
1731
                debugStatement();
1789
1732
/*
1790
1733
 *              $begin work;
1791
1734
 */
1792
 
#line 713 "dbinfx.ec"
 
1735
#line 656 "dbinfx.ec"
1793
1736
  {
1794
 
#line 713 "dbinfx.ec"
 
1737
#line 656 "dbinfx.ec"
1795
1738
  sqli_trans_begin2((mint)1);
1796
 
#line 713 "dbinfx.ec"
 
1739
#line 656 "dbinfx.ec"
1797
1740
  }
1798
1741
                if(errorTrap()) return;
1799
1742
        }
1806
1749
{
1807
1750
        rv_lastStatus = 0;
1808
1751
        checkConnect();
 
1752
stmt_text = 0;
1809
1753
 
1810
1754
        if(translevel == 0)
1811
1755
                errorPrint("2end transaction without a matching begTrans()");
1820
1764
/*
1821
1765
 *                      $commit work;
1822
1766
 */
1823
 
#line 736 "dbinfx.ec"
 
1767
#line 680 "dbinfx.ec"
1824
1768
  {
1825
 
#line 736 "dbinfx.ec"
 
1769
#line 680 "dbinfx.ec"
1826
1770
  sqli_trans_commit();
1827
 
#line 736 "dbinfx.ec"
 
1771
#line 680 "dbinfx.ec"
1828
1772
  }
1829
1773
                        if(ENGINE_ERRCODE) ++translevel;
1830
1774
                        errorTrap();
1837
1781
/*
1838
1782
 *                      $rollback work;
1839
1783
 */
1840
 
#line 745 "dbinfx.ec"
 
1784
#line 689 "dbinfx.ec"
1841
1785
  {
1842
 
#line 745 "dbinfx.ec"
 
1786
#line 689 "dbinfx.ec"
1843
1787
  sqli_trans_rollback();
1844
 
#line 745 "dbinfx.ec"
 
1788
#line 689 "dbinfx.ec"
1845
1789
  }
1846
1790
                        if(ENGINE_ERRCODE) --translevel;
1847
1791
                        errorTrap();
1869
1813
/*
1870
1814
 *      $set constraints all deferred;
1871
1815
 */
1872
 
#line 769 "dbinfx.ec"
 
1816
#line 713 "dbinfx.ec"
1873
1817
  {
1874
 
#line 769 "dbinfx.ec"
 
1818
#line 713 "dbinfx.ec"
1875
1819
  static const char *sqlcmdtxt[] =
1876
 
#line 769 "dbinfx.ec"
 
1820
#line 713 "dbinfx.ec"
1877
1821
    {
1878
 
#line 769 "dbinfx.ec"
 
1822
#line 713 "dbinfx.ec"
1879
1823
    "set constraints all deferred",
1880
1824
    0
1881
1825
    };
1882
 
#line 769 "dbinfx.ec"
 
1826
#line 713 "dbinfx.ec"
1883
1827
  static ifx_statement_t _SQ0 = {0};
1884
 
#line 769 "dbinfx.ec"
 
1828
#line 713 "dbinfx.ec"
1885
1829
  sqli_stmt(ESQLINTVERSION, &_SQ0, sqlcmdtxt, 0, (ifx_sqlvar_t *)0, (struct value *)0, (ifx_literal_t *)0, (ifx_namelist_t *)0, (ifx_cursor_t *)0, -1, 0, 0);
1886
 
#line 769 "dbinfx.ec"
 
1830
#line 713 "dbinfx.ec"
1887
1831
  }
1888
1832
        errorTrap();
1889
1833
        exclist = 0;
1906
1850
which makes sense only when the formatted string is destined for SQL.
1907
1851
*********************************************************************/
1908
1852
 
1909
 
/* information about the blob being fetched */
1910
 
const char *rv_blobFile;
1911
 
bool rv_blobAppend;
1912
 
void *rv_blobLoc; /* location of blob in memory */
1913
 
int rv_blobSize; /* size of blob in bytes */
1914
1853
static loc_t blobstruct; /* Informix structure to manage the blob */
1915
1854
 
1916
1855
/* insert a blob into the database */
1920
1859
/*
1921
1860
 * $char blobcmd[100];
1922
1861
 */
1923
 
#line 802 "dbinfx.ec"
 
1862
#line 741 "dbinfx.ec"
1924
1863
  char blobcmd[100];
1925
1864
/*
1926
1865
 * $loc_t insblob;
1927
1866
 */
1928
 
#line 803 "dbinfx.ec"
 
1867
#line 742 "dbinfx.ec"
1929
1868
  loc_t insblob;
1930
1869
 
1931
1870
/* basic sanity checks */
1964
1903
/*
1965
1904
 * $prepare blobinsert from :blobcmd;
1966
1905
 */
1967
 
#line 838 "dbinfx.ec"
 
1906
#line 777 "dbinfx.ec"
1968
1907
  {
1969
 
#line 838 "dbinfx.ec"
 
1908
#line 777 "dbinfx.ec"
1970
1909
  sqli_prep(ESQLINTVERSION, _Cn1, blobcmd,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 ); 
1971
 
#line 838 "dbinfx.ec"
 
1910
#line 777 "dbinfx.ec"
1972
1911
  }
1973
1912
if(errorTrap()) return;
1974
1913
/*
1975
1914
 * $execute blobinsert using :insblob;
1976
1915
 */
1977
 
#line 840 "dbinfx.ec"
 
1916
#line 779 "dbinfx.ec"
1978
1917
  {
1979
 
#line 840 "dbinfx.ec"
 
1918
#line 779 "dbinfx.ec"
1980
1919
  static ifx_sqlvar_t _sqibind[] = 
1981
1920
    {
1982
1921
      { 113, sizeof(insblob), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1983
 
#line 840 "dbinfx.ec"
 
1922
#line 779 "dbinfx.ec"
1984
1923
    };
1985
1924
  static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
1986
 
#line 840 "dbinfx.ec"
 
1925
#line 779 "dbinfx.ec"
1987
1926
  _sqibind[0].sqldata = (char *) &insblob;
1988
1927
  sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, _Cn1, 769), &_SD0, (char *)0, (struct value *)0, (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0);
1989
 
#line 840 "dbinfx.ec"
 
1928
#line 779 "dbinfx.ec"
1990
1929
  }
1991
1930
errorTrap();
1992
1931
rv_lastNrows = sqlca.sqlerrd[2];
2011
1950
The same for time intervals, money, etc.
2012
1951
*********************************************************************/
2013
1952
 
2014
 
/* Arrays that hold the return values from a select statement. */
2015
 
int rv_numRets; /* number of returned values */
2016
 
char rv_type[NUMRETS+1]; /* datatypes of returned values */
2017
 
char rv_name[NUMRETS+1][COLNAMELEN]; /* column names */
2018
 
LF  rv_data[NUMRETS]; /* the returned values */
2019
 
int rv_lastNrows, rv_lastRowid, rv_lastSerial;
2020
1953
/* Temp area to read the Informix values, as strings */
2021
1954
static char retstring[NUMRETS][STRINGLEN+4];
2022
1955
static va_list sqlargs;
2223
2156
if(!first) va_end(sqlargs);
2224
2157
} /* retsCopy */
2225
2158
 
2226
 
/* convert column name into column index */
2227
 
int findcol_byname(const char *name)
2228
 
{
2229
 
        int i;
2230
 
        for(i=0; rv_name[i][0]; ++i)
2231
 
                if(stringEqual(name, rv_name[i])) break;
2232
 
        if(!rv_name[i][0])
2233
 
                errorPrint("2Column %s not found in the columns or aliases of your select statement", name);
2234
 
        return i;
2235
 
} /* findcol_byname */
2236
 
 
2237
2159
/* make sure we got one return value, and it is integer compatible */
2238
2160
static long oneRetValue(void)
2239
2161
{
2261
2183
/*
2262
2184
 * $char*stmt = (char*)stmt_parm;
2263
2185
 */
2264
 
#line 1111 "dbinfx.ec"
 
2186
#line 1033 "dbinfx.ec"
2265
2187
  char *stmt = (char*)stmt_parm;
2266
2188
/*
2267
2189
 * $char*sname = (char*)sname_parm;
2268
2190
 */
2269
 
#line 1112 "dbinfx.ec"
 
2191
#line 1034 "dbinfx.ec"
2270
2192
  char *sname = (char*)sname_parm;
2271
2193
struct sqlda *desc;
2272
2194
struct sqlvar_struct   *v;
2295
2217
/*
2296
2218
 * $prepare :sname from :stmt;
2297
2219
 */
2298
 
#line 1137 "dbinfx.ec"
 
2220
#line 1059 "dbinfx.ec"
2299
2221
  {
2300
 
#line 1137 "dbinfx.ec"
 
2222
#line 1059 "dbinfx.ec"
2301
2223
  sqli_prep(ESQLINTVERSION, sname, stmt,(ifx_literal_t *)0, (ifx_namelist_t *)0, -1, 0, 0 ); 
2302
 
#line 1137 "dbinfx.ec"
 
2224
#line 1059 "dbinfx.ec"
2303
2225
  }
2304
2226
if(errorTrap()) return 0;
2305
2227
 
2307
2229
/*
2308
2230
 * $describe: sname into desc;
2309
2231
 */
2310
 
#line 1141 "dbinfx.ec"
 
2232
#line 1063 "dbinfx.ec"
2311
2233
  {
2312
 
#line 1141 "dbinfx.ec"
 
2234
#line 1063 "dbinfx.ec"
2313
2235
  sqli_describe_stmt(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, sname, 257), &desc, 0);
2314
 
#line 1141 "dbinfx.ec"
 
2236
#line 1063 "dbinfx.ec"
2315
2237
  }
2316
2238
if(!desc) errorPrint("2$describe couldn't allocate descriptor");
2317
2239
rv_numRets = desc->sqld;
2398
2320
/*
2399
2321
 * $static char singlestatement[] = "single_use_stmt";
2400
2322
 */
2401
 
#line 1224 "dbinfx.ec"
 
2323
#line 1146 "dbinfx.ec"
2402
2324
static   char singlestatement[] = "single_use_stmt";
2403
2325
/*
2404
2326
 * $static char singlecursor[] = "single_use_cursor";
2405
2327
 */
2406
 
#line 1225 "dbinfx.ec"
 
2328
#line 1147 "dbinfx.ec"
2407
2329
static   char singlecursor[] = "single_use_cursor";
2408
2330
int i;
2409
2331
bool notfound = false;
2420
2342
/*
2421
2343
 * $execute :singlestatement;
2422
2344
 */
2423
 
#line 1238 "dbinfx.ec"
 
2345
#line 1160 "dbinfx.ec"
2424
2346
  {
2425
 
#line 1238 "dbinfx.ec"
 
2347
#line 1160 "dbinfx.ec"
2426
2348
  sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 257), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0);
2427
 
#line 1238 "dbinfx.ec"
 
2349
#line 1160 "dbinfx.ec"
2428
2350
  }
2429
2351
notfound = true;
2430
2352
} else { /* end no return values */
2436
2358
/*
2437
2359
 * $execute: singlestatement into descriptor desc;
2438
2360
 */
2439
 
#line 1246 "dbinfx.ec"
 
2361
#line 1168 "dbinfx.ec"
2440
2362
  {
2441
 
#line 1246 "dbinfx.ec"
 
2363
#line 1168 "dbinfx.ec"
2442
2364
  sqli_exec(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 257), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, desc, (char *)0, (struct value *)0, 0);
2443
 
#line 1246 "dbinfx.ec"
 
2365
#line 1168 "dbinfx.ec"
2444
2366
  }
2445
2367
}
2446
2368
 
2459
2381
/*
2460
2382
 * $free :singlestatement;
2461
2383
 */
2462
 
#line 1261 "dbinfx.ec"
 
2384
#line 1183 "dbinfx.ec"
2463
2385
  {
2464
 
#line 1261 "dbinfx.ec"
 
2386
#line 1183 "dbinfx.ec"
2465
2387
  sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, singlestatement, 258));
2466
 
#line 1261 "dbinfx.ec"
 
2388
#line 1183 "dbinfx.ec"
2467
2389
  }
2468
2390
errorTrap();
2469
2391
nzFree(desc);
2487
2409
 
2488
2410
/* pointer to vararg list; most of these are vararg functions */
2489
2411
/* execute a stand-alone statement with no % formatting of the string */
2490
 
void sql_execNF(const char *stmt)
 
2412
bool sql_execNF(const char *stmt)
2491
2413
{
2492
 
        execInternal(stmt, 1);
 
2414
        return execInternal(stmt, 1);
2493
2415
} /* sql_execNF */
2494
2416
 
2495
2417
/* execute a stand-alone statement with % formatting */
2496
 
void sql_exec(const char *stmt, ...)
 
2418
bool sql_exec(const char *stmt, ...)
2497
2419
{
 
2420
bool ok;
2498
2421
        va_start(sqlargs, stmt);
2499
2422
        stmt = lineFormatStack(stmt, 0, &sqlargs);
2500
 
        execInternal(stmt, 1);
 
2423
        ok = execInternal(stmt, 1);
2501
2424
        va_end(sqlargs);
 
2425
return ok;
2502
2426
} /* sql_exec */
2503
2427
 
2504
2428
/* run a select statement with no % formatting of the string */
2580
2504
/*
2581
2505
 * $char *internal_sname, *internal_cname;
2582
2506
 */
2583
 
#line 1374 "dbinfx.ec"
 
2507
#line 1298 "dbinfx.ec"
2584
2508
  char *internal_sname, *internal_cname;
2585
2509
struct OCURS *o = findNewCursor();
2586
2510
 
2601
2525
/*
2602
2526
 * $declare :internal_cname scroll cursor with hold for :internal_sname;
2603
2527
 */
2604
 
#line 1391 "dbinfx.ec"
 
2528
#line 1315 "dbinfx.ec"
2605
2529
  {
2606
 
#line 1391 "dbinfx.ec"
 
2530
#line 1315 "dbinfx.ec"
2607
2531
  sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 0), internal_cname, sqli_curs_locate(ESQLINTVERSION, internal_sname, 1), 4128, 0);
2608
 
#line 1391 "dbinfx.ec"
 
2532
#line 1315 "dbinfx.ec"
2609
2533
  }
2610
2534
else
2611
2535
/*
2612
2536
 * $declare :internal_cname cursor with hold for :internal_sname;
2613
2537
 */
2614
 
#line 1393 "dbinfx.ec"
 
2538
#line 1317 "dbinfx.ec"
2615
2539
  {
2616
 
#line 1393 "dbinfx.ec"
 
2540
#line 1317 "dbinfx.ec"
2617
2541
  sqli_curs_decl_dynm(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 0), internal_cname, sqli_curs_locate(ESQLINTVERSION, internal_sname, 1), 4096, 0);
2618
 
#line 1393 "dbinfx.ec"
 
2542
#line 1317 "dbinfx.ec"
2619
2543
  }
2620
2544
if(errorTrap()) {
2621
2545
nzFree(o->desc);
2625
2549
o->numRets = rv_numRets;
2626
2550
memcpy(o->rv_type, rv_type, NUMRETS);
2627
2551
o->flag = CURSOR_PREPARED;
2628
 
o->fl = 0; /* just to make sure */
2629
2552
return o->cid;
2630
2553
} /* prepareCursor */
2631
2554
 
2653
2576
/*
2654
2577
 * $char *internal_sname, *internal_cname;
2655
2578
 */
2656
 
#line 1427 "dbinfx.ec"
 
2579
#line 1350 "dbinfx.ec"
2657
2580
  char *internal_sname, *internal_cname;
2658
2581
struct OCURS *o = findCursor(cid);
2659
2582
if(o->flag == CURSOR_OPENED)
2664
2587
/*
2665
2588
 * $open :internal_cname;
2666
2589
 */
2667
 
#line 1434 "dbinfx.ec"
 
2590
#line 1357 "dbinfx.ec"
2668
2591
  {
2669
 
#line 1434 "dbinfx.ec"
 
2592
#line 1357 "dbinfx.ec"
2670
2593
  sqli_curs_open(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, (char *)0, (struct value *)0, 0, 0);
2671
 
#line 1434 "dbinfx.ec"
 
2594
#line 1357 "dbinfx.ec"
2672
2595
  }
2673
2596
if(!errorTrap()) o->flag = CURSOR_OPENED;
2674
2597
o->rownum = 0;
2675
 
if(o->fl)
2676
 
for(i=0; i<o->alloc; ++i) {
2677
 
nzFree(o->fl[i]);
2678
 
o->fl[i] = 0;
2679
 
}
2680
2598
exclist = 0;
2681
2599
} /* sql_open */
2682
2600
 
2703
2621
/*
2704
2622
 * $char *internal_sname, *internal_cname;
2705
2623
 */
2706
 
#line 1465 "dbinfx.ec"
 
2624
#line 1383 "dbinfx.ec"
2707
2625
  char *internal_sname, *internal_cname;
2708
2626
struct OCURS *o = findCursor(cid);
2709
2627
if(o->flag < CURSOR_OPENED)
2713
2631
/*
2714
2632
 * $close :internal_cname;
2715
2633
 */
2716
 
#line 1471 "dbinfx.ec"
 
2634
#line 1389 "dbinfx.ec"
2717
2635
  {
2718
 
#line 1471 "dbinfx.ec"
 
2636
#line 1389 "dbinfx.ec"
2719
2637
  sqli_curs_close(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256));
2720
 
#line 1471 "dbinfx.ec"
 
2638
#line 1389 "dbinfx.ec"
2721
2639
  }
2722
2640
if(errorTrap()) return;
2723
2641
o->flag = CURSOR_PREPARED;
2724
2642
exclist = 0;
2725
2643
} /* sql_close */
2726
2644
 
2727
 
void sql_free( int cid)
 
2645
void
 
2646
sql_free( int cid)
2728
2647
{
2729
2648
/*
2730
2649
 * $char *internal_sname, *internal_cname;
2731
2650
 */
2732
 
#line 1479 "dbinfx.ec"
 
2651
#line 1398 "dbinfx.ec"
2733
2652
  char *internal_sname, *internal_cname;
2734
2653
struct OCURS *o = findCursor(cid);
2735
2654
if(o->flag == CURSOR_OPENED)
2739
2658
/*
2740
2659
 * $free :internal_sname;
2741
2660
 */
2742
 
#line 1485 "dbinfx.ec"
 
2661
#line 1404 "dbinfx.ec"
2743
2662
  {
2744
 
#line 1485 "dbinfx.ec"
 
2663
#line 1404 "dbinfx.ec"
2745
2664
  sqli_curs_free(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_sname, 258));
2746
 
#line 1485 "dbinfx.ec"
 
2665
#line 1404 "dbinfx.ec"
2747
2666
  }
2748
2667
if(errorTrap()) return;
2749
2668
o->flag = CURSOR_NONE;
2751
2670
rv_numRets = 0;
2752
2671
memset(rv_name, 0, sizeof(rv_name));
2753
2672
memset(rv_type, 0, sizeof(rv_type));
2754
 
if(o->fl) { /* free any cached lines */
2755
 
short i;
2756
 
for(i=0; i<o->alloc; ++i)
2757
 
nzFree(o->fl[i]);
2758
 
nzFree(o->fl);
2759
 
o->fl = 0;
2760
 
o->alloc = 0;
2761
 
}
2762
2673
exclist = 0;
2763
2674
} /* sql_free */
2764
2675
 
2774
2685
 
2775
2686
/* fetch row n from the open cursor.
2776
2687
 * Flag can be used to fetch first, last, next, or previous. */
2777
 
bool fetchInternal(int cid, long n, int flag, bool remember)
 
2688
static bool
 
2689
fetchInternal(int cid, long n, int flag, bool remember)
2778
2690
{
2779
2691
/*
2780
2692
 * $char *internal_sname, *internal_cname;
2781
2693
 */
2782
 
#line 1517 "dbinfx.ec"
 
2694
#line 1429 "dbinfx.ec"
2783
2695
  char *internal_sname, *internal_cname;
2784
2696
/*
2785
2697
 * $long nextrow, lastrow;
2786
2698
 */
2787
 
#line 1518 "dbinfx.ec"
 
2699
#line 1430 "dbinfx.ec"
2788
2700
long nextrow, lastrow;
2789
2701
struct sqlda *internal_desc;
2790
2702
struct OCURS *o = findCursor(cid);
2812
2724
}
2813
2725
if(flag == 4) { /* fetch the last row */
2814
2726
nextrow = nullint; /* we just lost track */
2815
 
if(o->fl && o->flag == CURSOR_PREPARED) {
2816
 
/* I'll assume you've read in all the rows, cursor is closed */
2817
 
for(nextrow=o->alloc-1; nextrow>=0; --nextrow)
2818
 
if(o->fl[nextrow]) break;
2819
 
++nextrow;
2820
 
}
2821
2727
}
2822
2728
 
2823
2729
if(!nextrow) goto fetchZero;
2824
2730
 
2825
 
/* see if we have cached this row */
2826
 
if(isnotnull(nextrow) && o->fl &&
2827
 
nextrow <= o->alloc && o->fl[nextrow-1]) {
2828
 
sql_mkload(o->fl[nextrow-1], '\177');
2829
 
/* don't run retsCleanup() here */
2830
 
rv_blobLoc = 0;
2831
 
rv_blobSize = nullint;
2832
 
o->rownum = nextrow;
2833
 
exclist = 0;
2834
 
return true;
2835
 
} /* bringing row out of cache */
2836
 
 
2837
2731
if(o->flag != CURSOR_OPENED)
2838
2732
errorPrint("2cannot fetch from cursor %d, not yet opened", cid);
2839
2733
 
2859
2753
/*
2860
2754
 * $fetch :internal_cname using descriptor internal_desc;
2861
2755
 */
2862
 
#line 1589 "dbinfx.ec"
 
2756
#line 1483 "dbinfx.ec"
2863
2757
  {
2864
 
#line 1589 "dbinfx.ec"
 
2758
#line 1483 "dbinfx.ec"
2865
2759
  static _FetchSpec _FS0 = { 0, 1, 0 };
2866
2760
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
2867
 
#line 1589 "dbinfx.ec"
 
2761
#line 1483 "dbinfx.ec"
2868
2762
  }
2869
2763
break;
2870
2764
case 2:
2871
2765
/*
2872
2766
 * $fetch previous :internal_cname using descriptor internal_desc;
2873
2767
 */
2874
 
#line 1592 "dbinfx.ec"
 
2768
#line 1486 "dbinfx.ec"
2875
2769
  {
2876
 
#line 1592 "dbinfx.ec"
 
2770
#line 1486 "dbinfx.ec"
2877
2771
  static _FetchSpec _FS0 = { 0, 2, 0 };
2878
2772
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
2879
 
#line 1592 "dbinfx.ec"
 
2773
#line 1486 "dbinfx.ec"
2880
2774
  }
2881
2775
break;
2882
2776
case 3:
2883
2777
/*
2884
2778
 * $fetch first :internal_cname using descriptor internal_desc;
2885
2779
 */
2886
 
#line 1595 "dbinfx.ec"
 
2780
#line 1489 "dbinfx.ec"
2887
2781
  {
2888
 
#line 1595 "dbinfx.ec"
 
2782
#line 1489 "dbinfx.ec"
2889
2783
  static _FetchSpec _FS0 = { 0, 3, 0 };
2890
2784
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
2891
 
#line 1595 "dbinfx.ec"
 
2785
#line 1489 "dbinfx.ec"
2892
2786
  }
2893
2787
break;
2894
2788
case 4:
2895
2789
/*
2896
2790
 * $fetch last :internal_cname using descriptor internal_desc;
2897
2791
 */
2898
 
#line 1598 "dbinfx.ec"
 
2792
#line 1492 "dbinfx.ec"
2899
2793
  {
2900
 
#line 1598 "dbinfx.ec"
 
2794
#line 1492 "dbinfx.ec"
2901
2795
  static _FetchSpec _FS0 = { 0, 4, 0 };
2902
2796
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), (ifx_sqlda_t *)0, internal_desc, (char *)0, &_FS0);
2903
 
#line 1598 "dbinfx.ec"
 
2797
#line 1492 "dbinfx.ec"
2904
2798
  }
2905
2799
break;
2906
2800
case 6:
2909
2803
/*
2910
2804
 * $fetch absolute :nextrow :internal_cname using descriptor internal_desc;
2911
2805
 */
2912
 
#line 1603 "dbinfx.ec"
 
2806
#line 1497 "dbinfx.ec"
2913
2807
  {
2914
 
#line 1603 "dbinfx.ec"
 
2808
#line 1497 "dbinfx.ec"
2915
2809
  static ifx_sqlvar_t _sqibind[] = 
2916
2810
    {
2917
2811
      { 103, sizeof(nextrow), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
2918
 
#line 1603 "dbinfx.ec"
 
2812
#line 1497 "dbinfx.ec"
2919
2813
    };
2920
2814
  static ifx_sqlda_t _SD0 = { 1, _sqibind, {0}, 1, 0 };
2921
2815
  static _FetchSpec _FS1 = { 0, 6, 0 };
2922
 
#line 1603 "dbinfx.ec"
 
2816
#line 1497 "dbinfx.ec"
2923
2817
  _sqibind[0].sqldata = (char *) &nextrow;
2924
2818
  sqli_curs_fetch(ESQLINTVERSION, sqli_curs_locate(ESQLINTVERSION, internal_cname, 256), &_SD0, internal_desc, (char *)0, &_FS1);
2925
 
#line 1603 "dbinfx.ec"
 
2819
#line 1497 "dbinfx.ec"
2926
2820
  }
2927
2821
break;
2928
2822
default:
2935
2829
if(ENGINE_ERRCODE == 100) return false; /* not found */
2936
2830
o->rownum = nextrow;
2937
2831
 
2938
 
/* remember the unload image of this line */
2939
 
if(remember)
2940
 
sql_cursorUpdLine(cid, cloneString(sql_mkunld('\177')));
2941
2832
return true;
2942
2833
} /* fetchInternal */
2943
2834
 
2987
2878
} /* sql_fetchAbs */
2988
2879
 
2989
2880
 
2990
 
/* the inverse of sql_mkunld() */
2991
 
void sql_mkload(const char *line, char delim)
2992
 
{
2993
 
char *s, *t;
2994
 
int data;
2995
 
short i;
2996
 
 
2997
 
for(i = 0, s = (char*)line; *s; ++i, *t=delim, s = t+1) {
2998
 
t = strchr(s, delim);
2999
 
if(!t) errorPrint("2sql load line does not end in a delimiter");
3000
 
*t = 0;
3001
 
if(i >= rv_numRets)
3002
 
errorPrint("2sql load line contains more than %d fields", rv_numRets);
3003
 
 
3004
 
switch(rv_type[i]) {
3005
 
case 'N':
3006
 
if(!*s) { data = nullint; break; }
3007
 
data = strtol(s, &s, 10);
3008
 
if(*s) errorPrint("2sql load, cannot convert string to integer");
3009
 
break;
3010
 
 
3011
 
case 'S':
3012
 
if((unsigned)strlen(s) > STRINGLEN)
3013
 
errorPrint("2sql load line has a string that is too long");
3014
 
strcpy(retstring[i], s);
3015
 
data = (int) retstring[i];
3016
 
if(!*s) data = 0;
3017
 
break;
3018
 
 
3019
 
case 'F':
3020
 
rv_data[i].f = *s ? atof(s) : nullfloat;
3021
 
continue;
3022
 
 
3023
 
case 'D':
3024
 
data = stringDate(s,0);
3025
 
if(data == -1)
3026
 
errorPrint("2sql load, cannot convert string to date");
3027
 
break;
3028
 
 
3029
 
case 'C':
3030
 
data = *s;
3031
 
if(data && s[1])
3032
 
errorPrint("2sql load, character field contains more than one character");
3033
 
break;
3034
 
 
3035
 
case 'I':
3036
 
data = stringTime(s);
3037
 
if(data == -1)
3038
 
errorPrint("2sql load, cannot convert string to time interval");
3039
 
break;
3040
 
 
3041
 
default:
3042
 
errorPrint("2sql load cannot convert into type %c", rv_type[i]);
3043
 
} /* switch on type */
3044
 
 
3045
 
rv_data[i].l = data;
3046
 
} /* loop over fields in line */
3047
 
 
3048
 
if(i != rv_numRets)
3049
 
errorPrint("2sql load line contains %d fields, %d expected", i, rv_numRets);
3050
 
} /* sql_mkload */
3051
 
 
3052
 
 
3053
 
/*********************************************************************
3054
 
We maintain our own cache of fetched lines.
3055
 
Why?  You might ask.
3056
 
After all, Informix already maintains a cache of fetched lines.
3057
 
That's what the open cursor is for.
3058
 
Looks like serious wheel reinvention to me.
3059
 
Perhaps, but you can't change the data in the cache that Informix maintains.
3060
 
This is something Powerbuild et al discovered over a decade ago.
3061
 
Consider a simple spreadsheet application.
3062
 
You update the value in one of the cells, thereby updating the row
3063
 
in the database.  Now scroll down to the next page, and then back again.
3064
 
If you fetch from the open cursor you will get the old data, before the
3065
 
change was made, even though the new data is safely ensconsed in the database.
3066
 
Granted one could reopen the cursor and fetch the new data,
3067
 
but this can be slow for certain queries (sometimes a couple minutes).
3068
 
In other words, rebuilding the cursor is not really an option.
3069
 
So we are forced to retain a copy of the data in our program and change it
3070
 
whenever we update the database.
3071
 
Unfortunately the following 3 routines were developed separately,
3072
 
and they are wildly inconsistent.  Some take a row number while
3073
 
others assume you are modifying the current row as stored in o->rownum.
3074
 
Some accept a line of tex, the unload image of the fetch data, while
3075
 
others build the line of text from the fetched data in rv_data[].
3076
 
I apologize for this confusion; clearly a redesign is called for.
3077
 
*********************************************************************/
3078
 
 
3079
 
/* update the text of a fetched line,
3080
 
 * so we get this same text again when we refetch the line later.
3081
 
 * These text changes corespond to the database changes that form an update.
3082
 
 * We assume the line has been allocated using malloc(). */
3083
 
void sql_cursorUpdLine(int cid, const char *line)
3084
 
{
3085
 
struct OCURS *o = findCursor(cid);
3086
 
int n = o->rownum-1;
3087
 
 
3088
 
if(n >= CACHELIMIT)
3089
 
errorPrint("2SQL cursor caches too many lines, limit %d", CACHELIMIT);
3090
 
 
3091
 
if(n >= o->alloc) {
3092
 
/* running off the end, allocate 128 at a time */
3093
 
short oldalloc = o->alloc;
3094
 
o->alloc = n + 128;
3095
 
if(!oldalloc)
3096
 
o->fl = (char **) allocMem(o->alloc*sizeof(char*));
3097
 
else
3098
 
o->fl = (char**) reallocMem((void*)o->fl, o->alloc*sizeof(char*));
3099
 
memset(o->fl+oldalloc, 0, (o->alloc-oldalloc)*sizeof(char*));
3100
 
} /* allocating more space */
3101
 
 
3102
 
nzFree(o->fl[n]);
3103
 
o->fl[n] = (char*)line;
3104
 
} /* sql_cursorUpdLine */
3105
 
 
3106
 
void sql_cursorDelLine(int cid, int rownum)
3107
 
{
3108
 
struct OCURS *o = findCursor(cid);
3109
 
o->rownum = rownum;
3110
 
--rownum;
3111
 
if(rownum >= o->alloc || !o->fl[rownum])
3112
 
errorPrint("2cursorDelLine(%d)", rownum);
3113
 
nzFree(o->fl[rownum]);
3114
 
if(rownum < o->alloc-1)
3115
 
memcpy(o->fl+rownum, o->fl+rownum+1, (o->alloc-rownum-1)*sizeof(char *));
3116
 
o->fl[o->alloc-1] = 0;
3117
 
/* back up the row number if we deleted the last row */
3118
 
if(!o->fl[rownum]) --o->rownum;
3119
 
} /* sql_cursorDelLine */
3120
 
 
3121
 
void sql_cursorInsLine(int cid, int rownum)
3122
 
{
3123
 
struct OCURS *o = findCursor(cid);
3124
 
short i;
3125
 
 
3126
 
/* must insert a row within or immediately following the current data */
3127
 
if(rownum > o->alloc)
3128
 
errorPrint("2cursorInsLine(%d)", rownum);
3129
 
/* newly inserted row becomes the current row */
3130
 
o->rownum = rownum+1;
3131
 
 
3132
 
if(!o->alloc || o->fl[o->alloc-1]) { /* need to make room */
3133
 
o->alloc += 128;
3134
 
if(!o->fl)
3135
 
o->fl = (char **) allocMem(o->alloc*sizeof(char*));
3136
 
else
3137
 
o->fl = (char**) reallocMem((void*)o->fl, o->alloc*sizeof(char*));
3138
 
memset(o->fl+o->alloc-128, 0, 128*sizeof(char*));
3139
 
} /* allocating more space */
3140
 
 
3141
 
/* move the rest of the lines down */
3142
 
for(i=o->alloc-1; i>rownum; --i)
3143
 
o->fl[i] = o->fl[i-1];
3144
 
o->fl[i] = cloneString(sql_mkunld('\177'));
3145
 
} /* sql_cursorInsLine */
3146
 
 
3147
 
 
3148
 
/*********************************************************************
3149
 
run the analog of /bin/comm on two open cursors,
3150
 
rather than two Unix files.
3151
 
This assumes a common unique key that we use to sync up the rows.
3152
 
The cursors should be sorted by this key.
3153
 
*********************************************************************/
3154
 
 
3155
 
void cursor_comm(
3156
 
const char *stmt1, const char *stmt2, /* the two select statements */
3157
 
const char *orderby, /* which fetched column is the unique key */
3158
 
fnptr f, /* call this function for differences */
3159
 
char delim) /* sql_mkunld() delimiter, or call mkinsupd if delim = 0 */
3160
 
{
3161
 
short cid1, cid2; /* the cursor ID numbers */
3162
 
char *line1, *line2, *s; /* the two fetched rows */
3163
 
void *blob1, *blob2; /* one blob per table */
3164
 
int blob1size, blob2size;
3165
 
bool eof1, eof2, get1, get2;
3166
 
int sortval1, sortval2;
3167
 
char sortstring1[80], sortstring2[80];
3168
 
int sortcol;
3169
 
char sorttype;
3170
 
int passkey1, passkey2;
3171
 
static const char sortnull[] = "cursor_comm, sortval%d is null";
3172
 
static const char sortlong[] = "cursor_comm cannot key on strings longer than %d";
3173
 
static const char noblob[] = "sorry, cursor_comm cannot handle blobs yet";
3174
 
 
3175
 
cid1 = sql_prepOpen(stmt1);
3176
 
cid2 = sql_prepOpen(stmt2);
3177
 
 
3178
 
sortcol = findcol_byname(orderby);
3179
 
sorttype = rv_type[sortcol];
3180
 
if(charInList("NDIS", sorttype) < 0)
3181
 
errorPrint("2cursor_com(), column %s has bad type %c", orderby, sorttype);
3182
 
if(sorttype == 'S')
3183
 
passkey1 = (int)sortstring1, passkey2 = (int)sortstring2;
3184
 
 
3185
 
eof1 = eof2 = false;
3186
 
get1 = get2 = true;
3187
 
rv_blobFile = 0; /* in case the cursor has a blob */
3188
 
line1 = line2 = 0;
3189
 
blob1 = blob2 = 0;
3190
 
 
3191
 
while(true) {
3192
 
if(get1) { /* fetch first row */
3193
 
eof1 = !sql_fetchNext(cid1, 0);
3194
 
nzFree(line1);
3195
 
line1 = 0;
3196
 
nzFree(blob1);
3197
 
blob1 = 0;
3198
 
if(!eof1) {
3199
 
if(sorttype == 'S') {
3200
 
s = rv_data[sortcol].ptr;
3201
 
if(isnullstring(s)) errorPrint(sortnull, 1);
3202
 
if(strlen(s) >= sizeof(sortstring1))
3203
 
errorPrint(sortlong, sizeof(sortstring1));
3204
 
strcpy(sortstring1, s);
3205
 
} else {
3206
 
passkey1 = sortval1 = rv_data[sortcol].l;
3207
 
if(isnull(sortval1))
3208
 
errorPrint(sortnull, 1);
3209
 
}
3210
 
line1 = cloneString(delim ? sql_mkunld(delim) : sql_mkinsupd());
3211
 
if(rv_blobLoc) {
3212
 
blob1 = rv_blobLoc;
3213
 
blob1size = rv_blobSize;
3214
 
errorPrint(noblob);
3215
 
}
3216
 
} /* not eof */
3217
 
} /* looking for first line */
3218
 
 
3219
 
if(get2) { /* fetch second row */
3220
 
eof2 = !sql_fetchNext(cid2, 0);
3221
 
nzFree(line2);
3222
 
line2 = 0;
3223
 
nzFree(blob2);
3224
 
blob2 = 0;
3225
 
if(!eof2) {
3226
 
if(sorttype == 'S') {
3227
 
s = rv_data[sortcol].ptr;
3228
 
if(isnullstring(s)) errorPrint(sortnull, 2);
3229
 
if(strlen(s) >= sizeof(sortstring2))
3230
 
errorPrint(sortlong, sizeof(sortstring2));
3231
 
strcpy(sortstring2, rv_data[sortcol].ptr);
3232
 
} else {
3233
 
passkey2 = sortval2 = rv_data[sortcol].l;
3234
 
if(isnull(sortval2))
3235
 
errorPrint(sortnull, 2);
3236
 
}
3237
 
line2 = cloneString(delim ? sql_mkunld(delim) : sql_mkinsupd());
3238
 
if(rv_blobLoc) {
3239
 
blob2 = rv_blobLoc;
3240
 
blob2size = rv_blobSize;
3241
 
errorPrint(noblob);
3242
 
}
3243
 
} /* not eof */
3244
 
} /* looking for second line */
3245
 
 
3246
 
if(eof1 & eof2) break; /* done */
3247
 
get1 = get2 = false;
3248
 
 
3249
 
/* in cid2, but not in cid1 */
3250
 
if(eof1 || !eof2 &&
3251
 
(sorttype == 'S' && strcmp(sortstring1, sortstring2) > 0 ||
3252
 
sorttype != 'S' && sortval1 > sortval2)) {
3253
 
(*f)('>', line1, line2, passkey2);
3254
 
get2 = true;
3255
 
continue;
3256
 
}
3257
 
 
3258
 
/* in cid1, but not in cid2 */
3259
 
if(eof2 || !eof1 &&
3260
 
(sorttype == 'S' && strcmp(sortstring1, sortstring2) < 0 ||
3261
 
sorttype != 'S' && sortval1 < sortval2)) {
3262
 
(*f)('<', line1, line2, passkey1);
3263
 
get1 = true;
3264
 
continue;
3265
 
} /* insert case */
3266
 
 
3267
 
get1 = get2 = true;
3268
 
/* perhaps the lines are equal */
3269
 
if(stringEqual(line1, line2)) continue;
3270
 
 
3271
 
/* lines are different between the two cursors */
3272
 
(*f)('*', line1, line2, passkey2);
3273
 
} /* loop over parallel cursors */
3274
 
 
3275
 
nzFree(line1);
3276
 
nzFree(line2);
3277
 
nzFree(blob1);
3278
 
nzFree(blob2);
3279
 
sql_closeFree(cid1);
3280
 
sql_closeFree(cid2);
3281
 
} /* cursor_comm */
3282
 
 
3283
2881
/*********************************************************************
3284
2882
Get the primary key for a table.
3285
2883
In informix, you can use system tables to get this information.
3286
 
There's a way to do it in odbc, but I don't remember.
 
2884
I haven't yet expanded this to a 3 part key.
3287
2885
*********************************************************************/
3288
2886
 
3289
2887
void
3290
 
getPrimaryKey(char *tname, int *part1, int *part2)
 
2888
getPrimaryKey(char *tname, int *part1, int *part2, int *part3)
3291
2889
{
3292
 
int p1, p2, rc;
3293
 
char *s = strchr(tname, ':');
3294
 
*part1 = *part2 = 0;
3295
 
if(!s) {
3296
 
rc = sql_select("select part1, part2 \
 
2890
    int p1, p2, rc;
 
2891
    char *s = strchr(tname, ':');
 
2892
    *part1 = *part2 = *part3 = 0;
 
2893
    if(!s) {
 
2894
        rc = sql_select("select part1, part2 \
3297
2895
from sysconstraints c, systables t, sysindexes i \
3298
2896
where tabname = %S and t.tabid = c.tabid \
3299
 
and constrtype = 'P' and c.idxname = i.idxname",
3300
 
tname, &p1, &p2);
3301
 
} else {
3302
 
*s = 0;
3303
 
rc = sql_select("select part1, part2 \
 
2897
and constrtype = 'P' and c.idxname = i.idxname", tname, &p1, &p2);
 
2898
    } else {
 
2899
        *s = 0;
 
2900
        rc = sql_select("select part1, part2 \
3304
2901
from %s:sysconstraints c, %s:systables t, %s:sysindexes i \
3305
2902
where tabname = %S and t.tabid = c.tabid \
3306
 
and constrtype = 'P' and c.idxname = i.idxname",
3307
 
tname, tname, tname, s+1, &p1, &p2);
3308
 
*s = ':';
3309
 
}
3310
 
if(rc) *part1 = p1, *part2 = p2;
3311
 
} /* getPrimaryKey */
3312
 
 
3313
 
 
3314
 
#line 1989 "dbinfx.ec"
 
2903
and constrtype = 'P' and c.idxname = i.idxname", tname, tname, tname, s + 1, &p1, &p2);
 
2904
        *s = ':';
 
2905
    }
 
2906
    if(rc)
 
2907
        *part1 = p1, *part2 = p2;
 
2908
}                               /* getPrimaryKey */
 
2909
 
 
2910
bool
 
2911
showTables(void)
 
2912
{
 
2913
puts("Not implemented in Informix, but certainly doable through systables");
 
2914
}                               /* showTables */
 
2915
 
 
2916
/* This can also be done by catalogs; it's on my list of things to do. */
 
2917
bool
 
2918
fetchForeign(char *tname)
 
2919
{
 
2920
i_puts(MSG_NYI);
 
2921
} /* fetchForeign */
 
2922
 
 
2923
#line 1598 "dbinfx.ec"