91
92
} /* sql_exception */
93
/* text descriptions corresponding to our generic SQL error codes */
94
static char *sqlErrorList[] = {0,
95
"miscelaneous SQL error",
96
"syntax error in SQL statement",
97
"filename cannot be used by SQL",
98
"cannot convert/compare the columns/constants in the SQL statement",
99
"bad string subscripting",
100
"bad use of the rowid construct",
101
"bad use of a blob column",
102
"bad use of aggregate operators or columns",
104
"bad use of a serial column",
105
"bad use of a temp table",
106
"operation cannot cross databases",
107
"database is fucked up",
108
"query interrupted by user",
109
"could not connect to the database",
110
"database has not yet been selected",
119
"constraint not found",
120
"duplicate constraint",
121
"stored procedure not found",
122
"duplicate stored procedure",
125
"table has no primary or unique key",
126
"duplicate primary or unique key",
127
"cursor not specified, or cursor is not available",
129
"the database lacks the resources needed to complete this query",
130
"check constrain violated",
131
"referential integrity violated",
132
"cannot manage or complete the transaction",
133
"long transaction, too much log data generated",
134
"this operation must be run inside a transaction",
135
"cannot open, read, write, close, or otherwise manage a blob",
136
"row, table, page, or database is already locked, or cannot be locked",
137
"inserting null into a not null column",
138
"no permission to modify the database in this way",
139
"no current row established",
140
"many rows were found where one was expected",
141
"cannot union these select statements together",
142
"cannot access or write the audit trail",
143
"could not run SQL or gather data from a remote host",
144
"where clause is semantically unmanageable",
148
/* map Informix errors to our own exception codes, as defined in c_sql.h. */
149
static struct ERRORMAP {
94
/* map Informix errors to our own exception codes, as defined in dbapi.h. */
95
static const struct ERRORMAP {
1664
1555
} /* sql_fetchAbs */
1667
/* the inverse of sql_mkunld() */
1668
void sql_mkload(const char *line, char delim)
1674
for(i = 0, s = (char*)line; *s; ++i, *t=delim, s = t+1) {
1675
t = strchr(s, delim);
1676
if(!t) errorPrint("2sql load line does not end in a delimiter");
1679
errorPrint("2sql load line contains more than %d fields", rv_numRets);
1681
switch(rv_type[i]) {
1683
if(!*s) { data = nullint; break; }
1684
data = strtol(s, &s, 10);
1685
if(*s) errorPrint("2sql load, cannot convert string to integer");
1689
if((unsigned)strlen(s) > STRINGLEN)
1690
errorPrint("2sql load line has a string that is too long");
1691
strcpy(retstring[i], s);
1692
data = (int) retstring[i];
1697
rv_data[i].f = *s ? atof(s) : nullfloat;
1701
data = stringDate(s,0);
1703
errorPrint("2sql load, cannot convert string to date");
1709
errorPrint("2sql load, character field contains more than one character");
1713
data = stringTime(s);
1715
errorPrint("2sql load, cannot convert string to time interval");
1719
errorPrint("2sql load cannot convert into type %c", rv_type[i]);
1720
} /* switch on type */
1722
rv_data[i].l = data;
1723
} /* loop over fields in line */
1726
errorPrint("2sql load line contains %d fields, %d expected", i, rv_numRets);
1730
/*********************************************************************
1731
We maintain our own cache of fetched lines.
1733
After all, Informix already maintains a cache of fetched lines.
1734
That's what the open cursor is for.
1735
Looks like serious wheel reinvention to me.
1736
Perhaps, but you can't change the data in the cache that Informix maintains.
1737
This is something Powerbuild et al discovered over a decade ago.
1738
Consider a simple spreadsheet application.
1739
You update the value in one of the cells, thereby updating the row
1740
in the database. Now scroll down to the next page, and then back again.
1741
If you fetch from the open cursor you will get the old data, before the
1742
change was made, even though the new data is safely ensconsed in the database.
1743
Granted one could reopen the cursor and fetch the new data,
1744
but this can be slow for certain queries (sometimes a couple minutes).
1745
In other words, rebuilding the cursor is not really an option.
1746
So we are forced to retain a copy of the data in our program and change it
1747
whenever we update the database.
1748
Unfortunately the following 3 routines were developed separately,
1749
and they are wildly inconsistent. Some take a row number while
1750
others assume you are modifying the current row as stored in o->rownum.
1751
Some accept a line of tex, the unload image of the fetch data, while
1752
others build the line of text from the fetched data in rv_data[].
1753
I apologize for this confusion; clearly a redesign is called for.
1754
*********************************************************************/
1756
/* update the text of a fetched line,
1757
* so we get this same text again when we refetch the line later.
1758
* These text changes corespond to the database changes that form an update.
1759
* We assume the line has been allocated using malloc(). */
1760
void sql_cursorUpdLine(int cid, const char *line)
1762
struct OCURS *o = findCursor(cid);
1763
int n = o->rownum-1;
1766
errorPrint("2SQL cursor caches too many lines, limit %d", CACHELIMIT);
1769
/* running off the end, allocate 128 at a time */
1770
short oldalloc = o->alloc;
1773
o->fl = (char **) allocMem(o->alloc*sizeof(char*));
1775
o->fl = (char**) reallocMem((void*)o->fl, o->alloc*sizeof(char*));
1776
memset(o->fl+oldalloc, 0, (o->alloc-oldalloc)*sizeof(char*));
1777
} /* allocating more space */
1780
o->fl[n] = (char*)line;
1781
} /* sql_cursorUpdLine */
1783
void sql_cursorDelLine(int cid, int rownum)
1785
struct OCURS *o = findCursor(cid);
1788
if(rownum >= o->alloc || !o->fl[rownum])
1789
errorPrint("2cursorDelLine(%d)", rownum);
1790
nzFree(o->fl[rownum]);
1791
if(rownum < o->alloc-1)
1792
memcpy(o->fl+rownum, o->fl+rownum+1, (o->alloc-rownum-1)*sizeof(char *));
1793
o->fl[o->alloc-1] = 0;
1794
/* back up the row number if we deleted the last row */
1795
if(!o->fl[rownum]) --o->rownum;
1796
} /* sql_cursorDelLine */
1798
void sql_cursorInsLine(int cid, int rownum)
1800
struct OCURS *o = findCursor(cid);
1803
/* must insert a row within or immediately following the current data */
1804
if(rownum > o->alloc)
1805
errorPrint("2cursorInsLine(%d)", rownum);
1806
/* newly inserted row becomes the current row */
1807
o->rownum = rownum+1;
1809
if(!o->alloc || o->fl[o->alloc-1]) { /* need to make room */
1812
o->fl = (char **) allocMem(o->alloc*sizeof(char*));
1814
o->fl = (char**) reallocMem((void*)o->fl, o->alloc*sizeof(char*));
1815
memset(o->fl+o->alloc-128, 0, 128*sizeof(char*));
1816
} /* allocating more space */
1818
/* move the rest of the lines down */
1819
for(i=o->alloc-1; i>rownum; --i)
1820
o->fl[i] = o->fl[i-1];
1821
o->fl[i] = cloneString(sql_mkunld('\177'));
1822
} /* sql_cursorInsLine */
1825
/*********************************************************************
1826
run the analog of /bin/comm on two open cursors,
1827
rather than two Unix files.
1828
This assumes a common unique key that we use to sync up the rows.
1829
The cursors should be sorted by this key.
1830
*********************************************************************/
1833
const char *stmt1, const char *stmt2, /* the two select statements */
1834
const char *orderby, /* which fetched column is the unique key */
1835
fnptr f, /* call this function for differences */
1836
char delim) /* sql_mkunld() delimiter, or call mkinsupd if delim = 0 */
1838
short cid1, cid2; /* the cursor ID numbers */
1839
char *line1, *line2, *s; /* the two fetched rows */
1840
void *blob1, *blob2; /* one blob per table */
1841
int blob1size, blob2size;
1842
bool eof1, eof2, get1, get2;
1843
int sortval1, sortval2;
1844
char sortstring1[80], sortstring2[80];
1847
int passkey1, passkey2;
1848
static const char sortnull[] = "cursor_comm, sortval%d is null";
1849
static const char sortlong[] = "cursor_comm cannot key on strings longer than %d";
1850
static const char noblob[] = "sorry, cursor_comm cannot handle blobs yet";
1852
cid1 = sql_prepOpen(stmt1);
1853
cid2 = sql_prepOpen(stmt2);
1855
sortcol = findcol_byname(orderby);
1856
sorttype = rv_type[sortcol];
1857
if(charInList("NDIS", sorttype) < 0)
1858
errorPrint("2cursor_com(), column %s has bad type %c", orderby, sorttype);
1860
passkey1 = (int)sortstring1, passkey2 = (int)sortstring2;
1862
eof1 = eof2 = false;
1864
rv_blobFile = 0; /* in case the cursor has a blob */
1869
if(get1) { /* fetch first row */
1870
eof1 = !sql_fetchNext(cid1, 0);
1876
if(sorttype == 'S') {
1877
s = rv_data[sortcol].ptr;
1878
if(isnullstring(s)) errorPrint(sortnull, 1);
1879
if(strlen(s) >= sizeof(sortstring1))
1880
errorPrint(sortlong, sizeof(sortstring1));
1881
strcpy(sortstring1, s);
1883
passkey1 = sortval1 = rv_data[sortcol].l;
1884
if(isnull(sortval1))
1885
errorPrint(sortnull, 1);
1887
line1 = cloneString(delim ? sql_mkunld(delim) : sql_mkinsupd());
1890
blob1size = rv_blobSize;
1894
} /* looking for first line */
1896
if(get2) { /* fetch second row */
1897
eof2 = !sql_fetchNext(cid2, 0);
1903
if(sorttype == 'S') {
1904
s = rv_data[sortcol].ptr;
1905
if(isnullstring(s)) errorPrint(sortnull, 2);
1906
if(strlen(s) >= sizeof(sortstring2))
1907
errorPrint(sortlong, sizeof(sortstring2));
1908
strcpy(sortstring2, rv_data[sortcol].ptr);
1910
passkey2 = sortval2 = rv_data[sortcol].l;
1911
if(isnull(sortval2))
1912
errorPrint(sortnull, 2);
1914
line2 = cloneString(delim ? sql_mkunld(delim) : sql_mkinsupd());
1917
blob2size = rv_blobSize;
1921
} /* looking for second line */
1923
if(eof1 & eof2) break; /* done */
1924
get1 = get2 = false;
1926
/* in cid2, but not in cid1 */
1928
(sorttype == 'S' && strcmp(sortstring1, sortstring2) > 0 ||
1929
sorttype != 'S' && sortval1 > sortval2)) {
1930
(*f)('>', line1, line2, passkey2);
1935
/* in cid1, but not in cid2 */
1937
(sorttype == 'S' && strcmp(sortstring1, sortstring2) < 0 ||
1938
sorttype != 'S' && sortval1 < sortval2)) {
1939
(*f)('<', line1, line2, passkey1);
1945
/* perhaps the lines are equal */
1946
if(stringEqual(line1, line2)) continue;
1948
/* lines are different between the two cursors */
1949
(*f)('*', line1, line2, passkey2);
1950
} /* loop over parallel cursors */
1956
sql_closeFree(cid1);
1957
sql_closeFree(cid2);
1960
1558
/*********************************************************************
1961
1559
Get the primary key for a table.
1962
1560
In informix, you can use system tables to get this information.
1963
There's a way to do it in odbc, but I don't remember.
1561
I haven't yet expanded this to a 3 part key.
1964
1562
*********************************************************************/
1967
getPrimaryKey(char *tname, int *part1, int *part2)
1565
getPrimaryKey(char *tname, int *part1, int *part2, int *part3)
1970
char *s = strchr(tname, ':');
1971
*part1 = *part2 = 0;
1973
rc = sql_select("select part1, part2 \
1568
char *s = strchr(tname, ':');
1569
*part1 = *part2 = *part3 = 0;
1571
rc = sql_select("select part1, part2 \
1974
1572
from sysconstraints c, systables t, sysindexes i \
1975
1573
where tabname = %S and t.tabid = c.tabid \
1976
and constrtype = 'P' and c.idxname = i.idxname",
1980
rc = sql_select("select part1, part2 \
1574
and constrtype = 'P' and c.idxname = i.idxname", tname, &p1, &p2);
1577
rc = sql_select("select part1, part2 \
1981
1578
from %s:sysconstraints c, %s:systables t, %s:sysindexes i \
1982
1579
where tabname = %S and t.tabid = c.tabid \
1983
and constrtype = 'P' and c.idxname = i.idxname",
1984
tname, tname, tname, s+1, &p1, &p2);
1987
if(rc) *part1 = p1, *part2 = p2;
1988
} /* getPrimaryKey */
1580
and constrtype = 'P' and c.idxname = i.idxname", tname, tname, tname, s + 1, &p1, &p2);
1584
*part1 = p1, *part2 = p2;
1585
} /* getPrimaryKey */
1590
puts("Not implemented in Informix, but certainly doable through systables");
1593
/* This can also be done by catalogs; it's on my list of things to do. */
1595
fetchForeign(char *tname)
1598
} /* fetchForeign */