DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (2b8c9e2f1f28)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-  */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1999
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Blake Ross (blake@blakeross.com)
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#ifndef _MDB_
#define _MDB_ 1

#include "mozilla/Path.h"
#include "nscore.h"
#include "nsISupports.h"
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

// { %%%%% begin scalar typedefs %%%%%
typedef unsigned char mdb_u1;   // make sure this is one byte
typedef unsigned short mdb_u2;  // make sure this is two bytes
typedef short mdb_i2;           // make sure this is two bytes
typedef uint32_t mdb_u4;        // make sure this is four bytes
typedef int32_t mdb_i4;         // make sure this is four bytes
typedef PRWord mdb_ip;          // make sure sizeof(mdb_ip) == sizeof(void*)

typedef mdb_u1 mdb_bool;  // unsigned byte with zero=false, nonzero=true

/* canonical boolean constants provided only for code clarity: */
#define mdbBool_kTrue ((mdb_bool)1)  /* actually any nonzero means true */
#define mdbBool_kFalse ((mdb_bool)0) /* only zero means false */

typedef mdb_u4 mdb_id;         // unsigned object identity in a scope
typedef mdb_id mdb_rid;        // unsigned row identity inside scope
typedef mdb_id mdb_tid;        // unsigned table identity inside scope
typedef mdb_u4 mdb_token;      // unsigned token for atomized string
typedef mdb_token mdb_scope;   // token used to id scope for rows
typedef mdb_token mdb_kind;    // token used to id kind for tables
typedef mdb_token mdb_column;  // token used to id columns for rows
typedef mdb_token mdb_cscode;  // token used to id charset names
typedef mdb_u4 mdb_seed;       // unsigned collection change counter
typedef mdb_u4 mdb_count;      // unsigned collection member count
typedef mdb_u4 mdb_size;       // unsigned physical media size
typedef mdb_u4 mdb_fill;       // unsigned logical content size
typedef mdb_u4 mdb_more;       // more available bytes for larger buffer

typedef mdb_u2 mork_uses;  // 2-byte strong uses count
typedef mdb_u2 mork_refs;  // 2-byte actual reference count

#define mdbId_kNone ((mdb_id)-1) /* never a valid Mork object ID */

typedef mdb_u4 mdb_percent;  // 0..100, with values >100 same as 100

typedef mdb_u1 mdb_priority;  // 0..9, for a total of ten different values

// sequence position is signed; negative is useful to mean "before first":
typedef mdb_i4 mdb_pos;  // signed zero-based ordinal collection position

#define mdbPos_kBeforeFirst ((mdb_pos)-1) /* any negative is before zero */

// order is also signed, so we can use three states for comparison order:
typedef mdb_i4 mdb_order;  // neg:lessthan, zero:equalto, pos:greaterthan

typedef mdb_order (*mdbAny_Order)(const void* inA, const void* inB,
                                  const void* inClosure);

// } %%%%% end scalar typedefs %%%%%

// { %%%%% begin C structs %%%%%

#ifndef mdbScopeStringSet_typedef
typedef struct mdbScopeStringSet mdbScopeStringSet;
#  define mdbScopeStringSet_typedef 1
#endif

/*| mdbScopeStringSet: a set of null-terminated C strings that enumerate some
**| names of row scopes, so that row scopes intended for use by an application
**| can be declared by an app when trying to open or create a database file.
**| (We use strings and not tokens because we cannot know the tokens for any
**| particular db without having first opened the db.)  The goal is to inform
**| a db runtime that scopes not appearing in this list can be given relatively
**| short shrift in runtime representation, with the expectation that other
**| scopes will not actually be used.  However, a db should still be prepared
**| to handle accessing row scopes not in this list, rather than raising errors.
**| But it could be quite expensive to access a row scope not on the list.
**| Note a zero count for the string set means no such string set is being
**| specified, and that a db should handle all row scopes efficiently.
**| (It does NOT mean an app plans to use no content whatsoever.)
|*/
#ifndef mdbScopeStringSet_struct
#  define mdbScopeStringSet_struct 1
struct mdbScopeStringSet {  // vector of scopes for use in db opening policy
  // when mScopeStringSet_Count is zero, this means no scope constraints
  mdb_count mScopeStringSet_Count;       // number of strings in vector below
  const char** mScopeStringSet_Strings;  // null-ended ascii scope strings
};
#endif /*mdbScopeStringSet_struct*/

#ifndef mdbOpenPolicy_typedef
typedef struct mdbOpenPolicy mdbOpenPolicy;
#  define mdbOpenPolicy_typedef 1
#endif

#ifndef mdbOpenPolicy_struct
#  define mdbOpenPolicy_struct 1
struct mdbOpenPolicy {  // policies affecting db usage for ports and stores
  mdbScopeStringSet mOpenPolicy_ScopePlan;  // predeclare scope usage plan
  mdb_bool mOpenPolicy_MaxLazy;             // nonzero: do least work
  mdb_bool mOpenPolicy_MinMemory;           // nonzero: use least memory
};
#endif /*mdbOpenPolicy_struct*/

#ifndef mdbTokenSet_typedef
typedef struct mdbTokenSet mdbTokenSet;
#  define mdbTokenSet_typedef 1
#endif

#ifndef mdbTokenSet_struct
#  define mdbTokenSet_struct 1
struct mdbTokenSet {  // array for a set of tokens, and actual slots used
  mdb_count mTokenSet_Count;    // number of token slots in the array
  mdb_fill mTokenSet_Fill;      // the subset of count slots actually used
  mdb_more mTokenSet_More;      // more tokens available for bigger array
  mdb_token* mTokenSet_Tokens;  // array of count mdb_token instances
};
#endif /*mdbTokenSet_struct*/

#ifndef mdbUsagePolicy_typedef
typedef struct mdbUsagePolicy mdbUsagePolicy;
#  define mdbUsagePolicy_typedef 1
#endif

/*| mdbUsagePolicy: another version of mdbOpenPolicy which uses tokens instead
**| of scope strings, because usage policies can be constructed for use with a
**| db that is already open, while an open policy must be constructed before a
**| db has yet been opened.
|*/
#ifndef mdbUsagePolicy_struct
#  define mdbUsagePolicy_struct 1
struct mdbUsagePolicy {  // policies affecting db usage for ports and stores
  mdbTokenSet mUsagePolicy_ScopePlan;  // current scope usage plan
  mdb_bool mUsagePolicy_MaxLazy;       // nonzero: do least work
  mdb_bool mUsagePolicy_MinMemory;     // nonzero: use least memory
};
#endif /*mdbUsagePolicy_struct*/

#ifndef mdbOid_typedef
typedef struct mdbOid mdbOid;
#  define mdbOid_typedef 1
#endif

#ifndef mdbOid_struct
#  define mdbOid_struct 1
struct mdbOid {          // identity of some row or table inside a database
  mdb_scope mOid_Scope;  // scope token for an id's namespace
  mdb_id mOid_Id;        // identity of object inside scope namespace
};
#endif /*mdbOid_struct*/

#ifndef mdbRange_typedef
typedef struct mdbRange mdbRange;
#  define mdbRange_typedef 1
#endif

#ifndef mdbRange_struct
#  define mdbRange_struct 1
struct mdbRange {           // range of row positions in a table
  mdb_pos mRange_FirstPos;  // position of first row
  mdb_pos mRange_LastPos;   // position of last row
};
#endif /*mdbRange_struct*/

#ifndef mdbColumnSet_typedef
typedef struct mdbColumnSet mdbColumnSet;
#  define mdbColumnSet_typedef 1
#endif

#ifndef mdbColumnSet_struct
#  define mdbColumnSet_struct 1
struct mdbColumnSet {  // array of column tokens (just the same as mdbTokenSet)
  mdb_count mColumnSet_Count;      // number of columns
  mdb_column* mColumnSet_Columns;  // count mdb_column instances
};
#endif /*mdbColumnSet_struct*/

#ifndef mdbYarn_typedef
typedef struct mdbYarn mdbYarn;
#  define mdbYarn_typedef 1
#endif

#ifdef MDB_BEGIN_C_LINKAGE_define
#  define MDB_BEGIN_C_LINKAGE_define 1
#  define MDB_BEGIN_C_LINKAGE extern "C" {
#  define MDB_END_C_LINKAGE }
#endif /*MDB_BEGIN_C_LINKAGE_define*/

/*| mdbYarn_mGrow: an abstract API for growing the size of a mdbYarn
**| instance.  With respect to a specific API that requires a caller
**| to supply a string (mdbYarn) that a callee fills with content
**| that might exceed the specified size, mdbYarn_mGrow is a caller-
**| supplied means of letting a callee attempt to increase the string
**| size to become large enough to receive all content available.
**|
**|| Grow(): a method for requesting that a yarn instance be made
**| larger in size.  Note that such requests need not be honored, and
**| need not be honored in full if only partial size growth is desired.
**| (Note that no nsIMdbEnv instance is passed as argument, although one
**| might be needed in some circumstances.  So if an nsIMdbEnv is needed,
**| a reference to one might be held inside a mdbYarn member slot.)
**|
**|| self: a yarn instance to be grown.  Presumably this yarn is
**| the instance which holds the mYarn_Grow method pointer.  Yarn
**| instancesshould only be passed to grow methods which they were
**| specifically designed to fit, as indicated by the mYarn_Grow slot.
**|
**|| inNewSize: the new desired value for slot mYarn_Size in self.
**| If mYarn_Size is already this big, then nothing should be done.
**| If inNewSize is larger than seems feasible or desirable to honor,
**| then any size restriction policy can be used to grow to some size
**| greater than mYarn_Size.  (Grow() might even grow to a size
**| greater than inNewSize in order to make the increase in size seem
**| worthwhile, rather than growing in many smaller steps over time.)
|*/
typedef void (*mdbYarn_mGrow)(mdbYarn* self, mdb_size inNewSize);
// mdbYarn_mGrow methods must be declared with C linkage in C++

/*| mdbYarn: a variable length "string" of arbitrary binary bytes,
**| whose length is mYarn_Fill, inside a buffer mYarn_Buf that has
**| at most mYarn_Size byte of physical space.
**|
**|| mYarn_Buf: a pointer to space containing content.  This slot
**| might never be nil when mYarn_Size is nonzero, but checks for nil
**| are recommended anyway.
**| (Implementations of mdbYarn_mGrow methods should take care to
**| ensure the existence of a replacement before dropping old Bufs.)
**| Content in Buf can be anything in any format, but the mYarn_Form
**| implies the actual format by some caller-to-callee convention.
**| mYarn_Form==0 implies US-ASCII iso-8859-1 Latin1 string content.
**|
**|| mYarn_Size: the physical size of Buf in bytes.  Note that if one
**| intends to terminate a string with a null byte, that it must not
**| be written at or after mYarn_Buf[mYarn_Size] because this is after
**| the last byte in the physical buffer space.  Size can be zero,
**| which means the string has no content whatsoever; note that when
**| Size is zero, this is a suitable reason for Buf==nil as well.
**|
**|| mYarn_Fill: the logical content in Buf in bytes, where Fill must
**| never exceed mYarn_Size.  Note that yarn strings might not have a
**| terminating null byte (since they might not even be C strings), but
**| when they do, such terminating nulls are considered part of content
**| and therefore Fill will count such null bytes.  So an "empty" C
**| string will have Fill==1, because content includes one null byte.
**| Fill does not mean "length" when applied to C strings for this
**| reason.  However, clients using yarns to hold C strings can infer
**| that length is equal to Fill-1 (but should take care to handle the
**| case where Fill==0).  To be paranoid, one can always copy to a
**| destination with size exceeding Fill, and place a redundant null
**| byte in the Fill position when this simplifies matters.
**|
**|| mYarn_Form: a designation of content format within mYarn_Buf.
**| The semantics of this slot are the least well defined, since the
**| actual meaning is context dependent, to the extent that callers
**| and callees must agree on format encoding conventions when such
**| are not standardized in many computing contexts.  However, in the
**| context of a specific mdb database, mYarn_Form is a token for an
**| atomized string in that database that typically names a preferred
**| mime type charset designation.  If and when mdbYarn is used for
**| other purposes away from the mdb interface, folks can use another
**| convention system for encoding content formats.  However, in all
**| contexts is it useful to maintain the convention that Form==0
**| implies Buf contains US-ASCII iso-8859-1 Latin1 string content.
**|
**|| mYarn_Grow: either a mdbYarn_mGrow method, or else nil.  When
**| a mdbYarn_mGrow method is provided, this method can be used to
**| request a yarn buf size increase.  A caller who constructs the
**| original mdbYarn instance decides whether a grow method is necessary
**| or desirable, and uses only grow methods suitable for the buffering
**| nature of a specific mdbYarn instance.  (For example, Buf might be a
**| statically allocated string space which switches to something heap-based
**| when grown, and subsequent calls to grow the yarn must distinguish the
**| original static string from heap allocated space, etc.) Note that the
**| method stored in mYarn_Grow can change, and this might be a common way
**| to track memory managent changes in policy for mYarn_Buf.
|*/
#ifndef mdbYarn_struct
#  define mdbYarn_struct 1
struct mdbYarn {             // buffer with caller space allocation semantics
  void* mYarn_Buf;           // space for holding any binary content
  mdb_fill mYarn_Fill;       // logical content in Buf in bytes
  mdb_size mYarn_Size;       // physical size of Buf in bytes
  mdb_more mYarn_More;       // more available bytes if Buf is bigger
  mdb_cscode mYarn_Form;     // charset format encoding
  mdbYarn_mGrow mYarn_Grow;  // optional method to grow mYarn_Buf

  // Subclasses might add further slots after mYarn_Grow in order to
  // maintain bookkeeping needs, such as state info about mYarn_Buf.
};
#endif /*mdbYarn_struct*/

// } %%%%% end C structs %%%%%

// { %%%%% begin class forward defines %%%%%
class nsIMdbEnv;
class nsIMdbObject;
class nsIMdbErrorHook;
class nsIMdbThumb;
class nsIMdbFactory;
class nsIMdbFile;
class nsIMdbPort;
class nsIMdbStore;
class nsIMdbCursor;
class nsIMdbPortTableCursor;
class nsIMdbCollection;
class nsIMdbTable;
class nsIMdbTableRowCursor;
class nsIMdbRow;
class nsIMdbRowCellCursor;
class nsIMdbBlob;
class nsIMdbCell;
class nsIMdbSorting;
// } %%%%% end class forward defines %%%%%

// { %%%%% begin C++ abstract class interfaces %%%%%

/*| nsIMdbObject: base class for all message db class interfaces
**|
**|| factory: all nsIMdbObjects from the same code suite have the same factory
**|
**|| refcounting: both strong and weak references, to ensure strong refs are
**| acyclic, while weak refs can cause cycles.  CloseMdbObject() is
**| called when (strong) use counts hit zero, but clients can call this close
**| method early for some reason, if absolutely necessary even though it will
**| thwart the other uses of the same object.  Note that implementations must
**| cope with close methods being called arbitrary numbers of times.  The COM
**| calls to AddRef() and release ref map directly to strong use ref calls,
**| but the total ref count for COM objects is the sum of weak & strong refs.
|*/

#define NS_IMDBOBJECT_IID_STR "5533ea4b-14c3-4bef-ac60-22f9e9a49084"

#define NS_IMDBOBJECT_IID                            \
  {                                                  \
    0x5533ea4b, 0x14c3, 0x4bef, {                    \
      0xac, 0x60, 0x22, 0xf9, 0xe9, 0xa4, 0x90, 0x84 \
    }                                                \
  }

class nsIMdbObject : public nsISupports {  // msg db base class
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBOBJECT_IID)
  // { ===== begin nsIMdbObject methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly) = 0;
  // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
  // } ----- end attribute methods -----

  // { ----- begin factory methods -----
  NS_IMETHOD GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory) = 0;
  // } ----- end factory methods -----

  // { ----- begin ref counting for well-behaved cyclic graphs -----
  NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev,  // weak refs
                             mdb_count* outCount) = 0;
  NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev,  // strong refs
                               mdb_count* outCount) = 0;

  NS_IMETHOD AddWeakRef(nsIMdbEnv* ev) = 0;
  NS_IMETHOD_(mork_uses) AddStrongRef(nsIMdbEnv* ev) = 0;

  NS_IMETHOD CutWeakRef(nsIMdbEnv* ev) = 0;
  NS_IMETHOD CutStrongRef(nsIMdbEnv* ev) = 0;

  NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev) = 0;  // called at strong refs zero
  NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen) = 0;
  // } ----- end ref counting -----

  // } ===== end nsIMdbObject methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbObject, NS_IMDBOBJECT_IID)

/*| nsIMdbErrorHook: a base class for clients of this API to subclass, in order
**| to provide a callback installable in nsIMdbEnv for error notifications. If
**| apps that subclass nsIMdbErrorHook wish to maintain a reference to the env
**| that contains the hook, then this should be a weak ref to avoid cycles.
**|
**|| OnError: when nsIMdbEnv has an error condition that causes the total count
**| of errors to increase, then nsIMdbEnv should call OnError() to report the
**| error in some fashion when an instance of nsIMdbErrorHook is installed.  The
**| variety of string flavors is currently due to the uncertainty here in the
**| nsIMdbBlob and nsIMdbCell interfaces.  (Note that overloading by using the
**| same method name is not necessary here, and potentially less clear.)
|*/
class nsIMdbErrorHook
    : public nsISupports {  // env callback handler to report errors
 public:
  // { ===== begin error methods =====
  NS_IMETHOD OnErrorString(nsIMdbEnv* ev, const char* inAscii) = 0;
  NS_IMETHOD OnErrorYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
  // } ===== end error methods =====

  // { ===== begin warning methods =====
  NS_IMETHOD OnWarningString(nsIMdbEnv* ev, const char* inAscii) = 0;
  NS_IMETHOD OnWarningYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
  // } ===== end warning methods =====

  // { ===== begin abort hint methods =====
  NS_IMETHOD OnAbortHintString(nsIMdbEnv* ev, const char* inAscii) = 0;
  NS_IMETHOD OnAbortHintYarn(nsIMdbEnv* ev, const mdbYarn* inYarn) = 0;
  // } ===== end abort hint methods =====
};

/*| nsIMdbHeap: abstract memory allocation interface.
**|
**|| Alloc: return a block at least inSize bytes in size with alignment
**| suitable for any native type (such as long integers).  When no such
**| block can be allocated, failure is indicated by a null address in
**| addition to reporting an error in the environment.
**|
**|| Free: deallocate a block allocated or resized earlier by the same
**| heap instance.  If the inBlock parameter is nil, the heap should do
**| nothing (and crashing is strongly discouraged).
|*/
class nsIMdbHeap {  // caller-supplied memory management interface
 public:
  // { ===== begin nsIMdbHeap methods =====
  NS_IMETHOD Alloc(nsIMdbEnv* ev,    // allocate a piece of memory
                   mdb_size inSize,  // requested byte size of new memory block
                   void** outBlock) =
      0;  // memory block of inSize bytes, or nil

  NS_IMETHOD Free(nsIMdbEnv* ev,       // free block from Alloc or Resize()
                  void* ioBlock) = 0;  // block to be destroyed/deallocated

  virtual size_t GetUsedSize() = 0;

  virtual ~nsIMdbHeap(){};
  // } ===== end nsIMdbHeap methods =====
};

/*| nsIMdbCPlusHeap: Alloc() with global ::new(), Free() with global ::delete().
**| Resize() is done by ::new() followed by ::delete().
|*/
class nsIMdbCPlusHeap {  // caller-supplied memory management interface
 public:
  // { ===== begin nsIMdbHeap methods =====
  NS_IMETHOD Alloc(nsIMdbEnv* ev,     // allocate a piece of memory
                   mdb_size inSize,   // requested size of new memory block
                   void** outBlock);  // memory block of inSize bytes, or nil

  NS_IMETHOD Free(nsIMdbEnv* ev,  // free block allocated earlier by Alloc()
                  void* inBlock);

  NS_IMETHOD HeapAddStrongRef(nsIMdbEnv* ev);
  NS_IMETHOD HeapCutStrongRef(nsIMdbEnv* ev);
  // } ===== end nsIMdbHeap methods =====
};

/*| nsIMdbThumb:
|*/

#define NS_IMDBTHUMB_IID_STR "6d3ad7c1-a809-4e74-8577-49fa9a4562fa"

#define NS_IMDBTHUMB_IID                             \
  {                                                  \
    0x6d3ad7c1, 0xa809, 0x4e74, {                    \
      0x85, 0x77, 0x49, 0xfa, 0x9a, 0x45, 0x62, 0xfa \
    }                                                \
  }

class nsIMdbThumb
    : public nsISupports {  // closure for repeating incremental method
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTHUMB_IID)

  // { ===== begin nsIMdbThumb methods =====
  NS_IMETHOD GetProgress(
      nsIMdbEnv* ev,
      mdb_count* outTotal,    // total somethings to do in operation
      mdb_count* outCurrent,  // subportion of total completed so far
      mdb_bool* outDone,      // is operation finished?
      mdb_bool* outBroken     // is operation irreparably dead and broken?
      ) = 0;

  NS_IMETHOD DoMore(
      nsIMdbEnv* ev,
      mdb_count* outTotal,    // total somethings to do in operation
      mdb_count* outCurrent,  // subportion of total completed so far
      mdb_bool* outDone,      // is operation finished?
      mdb_bool* outBroken     // is operation irreparably dead and broken?
      ) = 0;

  NS_IMETHOD CancelAndBreakThumb(  // cancel pending operation
      nsIMdbEnv* ev) = 0;
  // } ===== end nsIMdbThumb methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbThumb, NS_IMDBTHUMB_IID)

/*| nsIMdbEnv: a context parameter used when calling most abstract db methods.
**| The main purpose of such an object is to permit a database implementation
**| to avoid the use of globals to share information between various parts of
**| the implementation behind the abstract db interface.  An environment acts
**| like a session object for a given calling thread, and callers should use
**| at least one different nsIMdbEnv instance for each thread calling the API.
**| While the database implementation might not be threaded, it is highly
**| desirable that the db be thread-safe if calling threads use distinct
**| instances of nsIMdbEnv.  Callers can stop at one nsIMdbEnv per thread, or
they
**| might decide to make on nsIMdbEnv instance for every nsIMdbPort opened, so
that
**| error information is segregated by database instance.  Callers create
**| instances of nsIMdbEnv by calling the MakeEnv() method in nsIMdbFactory.
**|
**|| tracing: an environment might support some kind of tracing, and this
**| boolean attribute permits such activity to be enabled or disabled.
**|
**|| errors: when a call to the abstract db interface returns, a caller might
**| check the number of outstanding errors to see whether the operation did
**| actually succeed. Each nsIMdbEnv should have all its errors cleared by a
**| call to ClearErrors() before making each call to the abstract db API,
**| because outstanding errors might disable further database actions.  (This
**| is not done inside the db interface, because the db cannot in general know
**| when a call originates from inside or outside -- only the app knows this.)
**|
**|| error hook: callers can install an instance of nsIMdbErrorHook to receive
**| error notifications whenever the error count increases.  The hook can
**| be uninstalled by passing a null pointer.
**|
|*/

#define NS_IMDBENV_IID_STR "a765e46b-efb6-41e6-b75b-c5d6bd710594"

#define NS_IMDBENV_IID                               \
  {                                                  \
    0xa765e46b, 0xefb6, 0x41e6, {                    \
      0xb7, 0x5b, 0xc5, 0xd6, 0xbd, 0x71, 0x05, 0x94 \
    }                                                \
  }

class nsIMdbEnv : public nsISupports {  // db specific context parameter
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBENV_IID)
  // { ===== begin nsIMdbEnv methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD GetErrorCount(mdb_count* outCount, mdb_bool* outShouldAbort) = 0;
  NS_IMETHOD GetWarningCount(mdb_count* outCount, mdb_bool* outShouldAbort) = 0;

  NS_IMETHOD GetEnvBeVerbose(mdb_bool* outBeVerbose) = 0;
  NS_IMETHOD SetEnvBeVerbose(mdb_bool inBeVerbose) = 0;

  NS_IMETHOD GetDoTrace(mdb_bool* outDoTrace) = 0;
  NS_IMETHOD SetDoTrace(mdb_bool inDoTrace) = 0;

  NS_IMETHOD GetAutoClear(mdb_bool* outAutoClear) = 0;
  NS_IMETHOD SetAutoClear(mdb_bool inAutoClear) = 0;

  NS_IMETHOD GetErrorHook(nsIMdbErrorHook** acqErrorHook) = 0;
  NS_IMETHOD SetErrorHook(nsIMdbErrorHook* ioErrorHook) =
      0;  // becomes referenced

  NS_IMETHOD GetHeap(nsIMdbHeap** acqHeap) = 0;
  NS_IMETHOD SetHeap(nsIMdbHeap* ioHeap) = 0;  // becomes referenced
  // } ----- end attribute methods -----

  NS_IMETHOD ClearErrors() = 0;    // clear errors beore re-entering db API
  NS_IMETHOD ClearWarnings() = 0;  // clear warnings
  NS_IMETHOD ClearErrorsAndWarnings() = 0;  // clear both errors & warnings
  // } ===== end nsIMdbEnv methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbEnv, NS_IMDBENV_IID)

/*| nsIMdbFactory: the main entry points to the abstract db interface.  A DLL
**| that supports this mdb interface need only have a single exported method
**| that will return an instance of nsIMdbFactory, so that further methods in
**| the suite can be accessed from objects returned by nsIMdbFactory methods.
**|
**|| mdbYarn: note all nsIMdbFactory subclasses must guarantee null
**| termination of all strings written into mdbYarn instances, as long as
**| mYarn_Size and mYarn_Buf are nonzero.  Even truncated string values must
**| be null terminated.  This is more strict behavior than mdbYarn requires,
**| but it is part of the nsIMdbFactory interface.
**|
**|| envs: an environment instance is required as per-thread context for
**| most of the db method calls, so nsIMdbFactory creates such instances.
**|
**|| rows: callers must be able to create row instances that are independent
**| of storage space that is part of the db content graph.  Many interfaces
**| for data exchange have strictly copy semantics, so that a row instance
**| has no specific identity inside the db content model, and the text in
**| cells are an independenty copy of unexposed content inside the db model.
**| Callers are expected to maintain one or more row instances as a buffer
**| for staging cell content copied into or out of a table inside the db.
**| Callers are urged to use an instance of nsIMdbRow created by the
nsIMdbFactory
**| code suite, because reading and writing might be much more efficient than
**| when using a hand-rolled nsIMdbRow subclass with no relation to the suite.
**|
**|| ports: a port is a readonly interface to a specific database file. Most
**| of the methods to access a db file are suitable for a readonly interface,
**| so a port is the basic minimum for accessing content.  This makes it
**| possible to read other external formats for import purposes, without
**| needing the code or competence necessary to write every such format.  So
**| we can write generic import code just once, as long as every format can
**| show a face based on nsIMdbPort. (However, same suite import can be faster.)
**| Given a file name and the first 512 bytes of a file, a factory can say if
**| a port can be opened by this factory.  Presumably an app maintains chains
**| of factories for different suites, and asks each in turn about opening a
**| a prospective file for reading (as a port) or writing (as a store).  I'm
**| not ready to tackle issues of format fidelity and factory chain ordering.
**|
**|| stores: a store is a mutable interface to a specific database file, and
**| includes the port interface plus any methods particular to writing, which
**| are few in number.  Presumably the set of files that can be opened as
**| stores is a subset of the set of files that can be opened as ports.  A
**| new store can be created with CreateNewFileStore() by supplying a new
**| file name which does not yet exist (callers are always responsible for
**| destroying any existing files before calling this method).
|*/

#define NS_IMDBFACTORY_IID_STR "2b80395c-b91e-4990-b1a7-023e99ab14e9"

#define NS_IMDBFACTORY_IID                           \
  {                                                  \
    0xf04aa4ab, 0x1fe, 0x4115, {                     \
      0xa4, 0xa5, 0x68, 0x19, 0xdf, 0xf1, 0x10, 0x3d \
    }                                                \
  }

class nsIMdbFactory : public nsISupports {  // suite entry points
  using PathChar = mozilla::filesystem::Path::value_type;

 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFACTORY_IID)
  // { ===== begin nsIMdbFactory methods =====

  // { ----- begin file methods -----
  NS_IMETHOD OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
                         const PathChar* inFilePath, mdb_bool inFrozen,
                         nsIMdbFile** acqFile) = 0;
  // Choose some subclass of nsIMdbFile to instantiate, in order to read
  // (and write if not frozen) the file known by inFilePath.  The file
  // returned should be open and ready for use, and presumably positioned
  // at the first byte position of the file.  The exact manner in which
  // files must be opened is considered a subclass specific detail, and
  // other portions or Mork source code don't want to know how it's done.

  NS_IMETHOD CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
                           const PathChar* inFilePath,
                           nsIMdbFile** acqFile) = 0;
  // Choose some subclass of nsIMdbFile to instantiate, in order to read
  // (and write if not frozen) the file known by inFilePath.  The file
  // returned should be created and ready for use, and presumably positioned
  // at the first byte position of the file.  The exact manner in which
  // files must be opened is considered a subclass specific detail, and
  // other portions or Mork source code don't want to know how it's done.
  // } ----- end file methods -----

  // { ----- begin env methods -----
  NS_IMETHOD MakeEnv(nsIMdbHeap* ioHeap,
                     nsIMdbEnv** acqEnv) = 0;  // acquire new env
  // ioHeap can be nil, causing a MakeHeap() style heap instance to be used
  // } ----- end env methods -----

  // { ----- begin heap methods -----
  NS_IMETHOD MakeHeap(nsIMdbEnv* ev,
                      nsIMdbHeap** acqHeap) = 0;  // acquire new heap
  // } ----- end heap methods -----

  // { ----- begin row methods -----
  NS_IMETHOD MakeRow(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
                     nsIMdbRow** acqRow) = 0;  // new row
  // ioHeap can be nil, causing the heap associated with ev to be used
  // } ----- end row methods -----

  // { ----- begin port methods -----
  NS_IMETHOD CanOpenFilePort(
      nsIMdbEnv* ev,  // context
      // const char* inFilePath, // the file to investigate
      // const mdbYarn* inFirst512Bytes,
      nsIMdbFile* ioFile,              // db abstract file interface
      mdb_bool* outCanOpen,            // whether OpenFilePort() might succeed
      mdbYarn* outFormatVersion) = 0;  // informal file format description

  NS_IMETHOD OpenFilePort(
      nsIMdbEnv* ev,       // context
      nsIMdbHeap* ioHeap,  // can be nil to cause ev's heap attribute to be used
      // const char* inFilePath, // the file to open for readonly import
      nsIMdbFile* ioFile,                 // db abstract file interface
      const mdbOpenPolicy* inOpenPolicy,  // runtime policies for using db
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental port open
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then call nsIMdbFactory::ThumbToOpenPort() to get the port instance.

  NS_IMETHOD
  ThumbToOpenPort(           // redeeming a completed thumb from OpenFilePort()
      nsIMdbEnv* ev,         // context
      nsIMdbThumb* ioThumb,  // thumb from OpenFilePort() with done status
      nsIMdbPort** acqPort) = 0;  // acquire new port object
  // } ----- end port methods -----

  // { ----- begin store methods -----
  NS_IMETHOD CanOpenFileStore(
      nsIMdbEnv* ev,  // context
      // const char* inFilePath, // the file to investigate
      // const mdbYarn* inFirst512Bytes,
      nsIMdbFile* ioFile,              // db abstract file interface
      mdb_bool* outCanOpenAsStore,     // whether OpenFileStore() might succeed
      mdb_bool* outCanOpenAsPort,      // whether OpenFilePort() might succeed
      mdbYarn* outFormatVersion) = 0;  // informal file format description

  NS_IMETHOD OpenFileStore(  // open an existing database
      nsIMdbEnv* ev,         // context
      nsIMdbHeap* ioHeap,  // can be nil to cause ev's heap attribute to be used
      // const char* inFilePath, // the file to open for general db usage
      nsIMdbFile* ioFile,                 // db abstract file interface
      const mdbOpenPolicy* inOpenPolicy,  // runtime policies for using db
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental store open
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then call nsIMdbFactory::ThumbToOpenStore() to get the store instance.

  NS_IMETHOD
  ThumbToOpenStore(          // redeem completed thumb from OpenFileStore()
      nsIMdbEnv* ev,         // context
      nsIMdbThumb* ioThumb,  // thumb from OpenFileStore() with done status
      nsIMdbStore** acqStore) = 0;  // acquire new db store object

  NS_IMETHOD CreateNewFileStore(  // create a new db with minimal content
      nsIMdbEnv* ev,              // context
      nsIMdbHeap* ioHeap,  // can be nil to cause ev's heap attribute to be used
      // const char* inFilePath, // name of file which should not yet exist
      nsIMdbFile* ioFile,                 // db abstract file interface
      const mdbOpenPolicy* inOpenPolicy,  // runtime policies for using db
      nsIMdbStore** acqStore) = 0;        // acquire new db store object
  // } ----- end store methods -----

  // } ===== end nsIMdbFactory methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFactory, NS_IMDBFACTORY_IID)

extern "C" nsIMdbFactory* MakeMdbFactory();

/*| nsIMdbFile: abstract file interface resembling the original morkFile
**| abstract interface (which was in turn modeled on the file interface
**| from public domain IronDoc).  The design of this file interface is
**| complicated by the fact that some DB's will not find this interface
**| adequate for all runtime requirements (even though this file API is
**| enough to implement text-based DB's like Mork).  For this reason,
**| more methods have been added to let a DB library force the file to
**| become closed so the DB can reopen the file in some other manner.
**| Folks are encouraged to suggest ways to tune this interface to suit
**| DB's that cannot manage to pull their maneuvers even given this API.
**|
**|| Tell: get the current i/o position in file
**|
**|| Seek: change the current i/o position in file
**|
**|| Eof: return file's total length in bytes
**|
**|| Read: input inSize bytes into outBuf, returning actual transfer size
**|
**|| Get: read starting at specific file offset (e.g. Seek(); Read();)
**|
**|| Write: output inSize bytes from inBuf, returning actual transfer size
**|
**|| Put: write starting at specific file offset (e.g. Seek(); Write();)
**|
**|| Flush: if written bytes are buffered, push them to final destination
**|
**|| Path: get file path in some string representation.  This is intended
**| either to support the display of file name in a user presentation, or
**| to support the closing and reopening of the file when the DB needs more
**| exotic file access than is presented by the nsIMdbFile interface.
**|
**|| Steal: tell this file to close any associated i/o stream in the file
**| system, because the file ioThief intends to reopen the file in order
**| to provide the MDB implementation with more exotic file access than is
**| offered by the nsIMdbFile alone.  Presumably the thief knows enough
**| from Path() in order to know which file to reopen.  If Steal() is
**| successful, this file should probably delegate all future calls to
**| the nsIMdbFile interface down to the thief files, so that even after
**| the file has been stolen, it can still be read, written, or forcibly
**| closed (by a call to CloseMdbObject()).
**|
**|| Thief: acquire and return thief passed to an earlier call to Steal().
|*/

#define NS_IMDBFILE_IID_STR "f04aa4ab-1fe7-4115-a4a5-6819dff1103d"

#define NS_IMDBFILE_IID                              \
  {                                                  \
    0xf04aa4ab, 0x1fe, 0x4115, {                     \
      0xa4, 0xa5, 0x68, 0x19, 0xdf, 0xf1, 0x10, 0x3d \
    }                                                \
  }

class nsIMdbFile : public nsISupports {  // minimal file interface
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFILE_IID)
  // { ===== begin nsIMdbFile methods =====

  // { ----- begin pos methods -----
  NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
  NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos* outPos) = 0;
  NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
  // } ----- end pos methods -----

  // { ----- begin read methods -----
  NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
                  mdb_size* outActualSize) = 0;
  NS_IMETHOD Get(nsIMdbEnv* ev, void* outBuf, mdb_size inSize, mdb_pos inPos,
                 mdb_size* outActualSize) = 0;
  // } ----- end read methods -----

  // { ----- begin write methods -----
  NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
                   mdb_size* outActualSize) = 0;
  NS_IMETHOD Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
                 mdb_pos inPos, mdb_size* outActualSize) = 0;
  NS_IMETHOD Flush(nsIMdbEnv* ev) = 0;
  // } ----- end attribute methods -----

  // { ----- begin path methods -----
  NS_IMETHOD Path(nsIMdbEnv* ev, mdbYarn* outFilePath) = 0;
  // } ----- end path methods -----

  // { ----- begin replacement methods -----
  NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) = 0;
  NS_IMETHOD Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief) = 0;
  // } ----- end replacement methods -----

  // { ----- begin versioning methods -----
  NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) = 0;
  // If this file is a file version branch created by calling AcquireBud(),
  // BecomeTrunk() causes this file's content to replace the original
  // file's content, typically by assuming the original file's identity.
  // This default implementation of BecomeTrunk() does nothing, and this
  // is appropriate behavior for files which are not branches, and is
  // also the right behavior for files returned from AcquireBud() which are
  // in fact the original file that has been truncated down to zero length.

  NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
                        nsIMdbFile** acqBud) =
      0;  // acquired file for new version of content
  // AcquireBud() starts a new "branch" version of the file, empty of content,
  // so that a new version of the file can be written.  This new file
  // can later be told to BecomeTrunk() the original file, so the branch
  // created by budding the file will replace the original file.  Some
  // file subclasses might initially take the unsafe but expedient
  // approach of simply truncating this file down to zero length, and
  // then returning the same morkFile pointer as this, with an extra
  // reference count increment.  Note that the caller of AcquireBud() is
  // expected to eventually call CutStrongRef() on the returned file
  // in order to release the strong reference.  High quality versions
  // of morkFile subclasses will create entirely new files which later
  // are renamed to become the old file, so that better transactional
  // behavior is exhibited by the file, so crashes protect old files.
  // Note that AcquireBud() is an illegal operation on readonly files.
  // } ----- end versioning methods -----

  // } ===== end nsIMdbFile methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFile, NS_IMDBFILE_IID)

/*| nsIMdbPort: a readonly interface to a specific database file. The mutable
**| nsIMdbStore interface is a subclass that includes writing behavior, but
**| most of the needed db methods appear in the readonly nsIMdbPort interface.
**|
**|| mdbYarn: note all nsIMdbPort and nsIMdbStore subclasses must guarantee null
**| termination of all strings written into mdbYarn instances, as long as
**| mYarn_Size and mYarn_Buf are nonzero.  Even truncated string values must
**| be null terminated.  This is more strict behavior than mdbYarn requires,
**| but it is part of the nsIMdbPort and nsIMdbStore interface.
**|
**|| attributes: methods are provided to distinguish a readonly port from a
**| mutable store, and whether a mutable store actually has any dirty content.
**|
**|| filepath: the file path used to open the port from the nsIMdbFactory can be
**| queried and discovered by GetPortFilePath(), which includes format info.
**|
**|| export: a port can write itself in other formats, with perhaps a typical
**| emphasis on text interchange formats used by other systems.  A port can be
**| queried to determine its preferred export interchange format, and a port
**| can be queried to see whether a specific export format is supported.  And
**| actually exporting a port requires a new destination file name and format.
**|
**|| tokens: a port supports queries about atomized strings to map tokens to
**| strings or strings to token integers.  (All atomized strings must be in
**| US-ASCII iso-8859-1 Latin1 charset encoding.)  When a port is actually a
**| mutable store and a string has not yet been atomized, then StringToToken()
**| will actually do so and modify the store.  The QueryToken() method will not
**| atomize a string if it has not already been atomized yet, even in stores.
**|
**|| tables: other than string tokens, all port content is presented through
**| tables, which are ordered collections of rows.  Tables are identified by
**| row scope and table kind, which might or might not be unique in a port,
**| depending on app convention.  When tables are effectively unique, then
**| queries for specific scope and kind pairs will find those tables.  To see
**| all tables that match specific row scope and table kind patterns, even in
**| the presence of duplicates, every port supports a GetPortTableCursor()
**| method that returns an iterator over all matching tables.  Table kind is
**| considered scoped inside row scope, so passing a zero for table kind will
**| find all table kinds for some nonzero row scope.  Passing a zero for row
**| scope will iterate over all tables in the port, in some undefined order.
**| (A new table can be added to a port using nsIMdbStore::NewTable(), even when
**| the requested scope and kind combination is already used by other tables.)
**|
**|| memory: callers can request that a database use less memory footprint in
**| several flavors, from an inconsequential idle flavor to a rather drastic
**| panic flavor. Callers might perform an idle purge very frequently if desired
**| with very little cost, since only normally scheduled memory management will
**| be conducted, such as freeing resources for objects scheduled to be dropped.
**| Callers should perform session memory purges infrequently because they might
**| involve costly scanning of data structures to removed cached content, and
**| session purges are recommended only when a caller experiences memory crunch.
**| Callers should only rarely perform a panic purge, in response to dire memory
**| straits, since this is likely to make db operations much more expensive
**| than they would be otherwise.  A panic purge asks a database to free as much
**| memory as possible while staying effective and operational, because a caller
**| thinks application failure might otherwise occur.  (Apps might better close
**| an open db, so panic purges only make sense when a db is urgently needed.)
|*/
class nsIMdbPort : public nsISupports {
 public:
  // { ===== begin nsIMdbPort methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD GetIsPortReadonly(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
  NS_IMETHOD GetIsStore(nsIMdbEnv* ev, mdb_bool* outBool) = 0;
  NS_IMETHOD GetIsStoreAndDirty(nsIMdbEnv* ev, mdb_bool* outBool) = 0;

  NS_IMETHOD GetUsagePolicy(nsIMdbEnv* ev, mdbUsagePolicy* ioUsagePolicy) = 0;

  NS_IMETHOD SetUsagePolicy(nsIMdbEnv* ev,
                            const mdbUsagePolicy* inUsagePolicy) = 0;
  // } ----- end attribute methods -----

  // { ----- begin memory policy methods -----
  NS_IMETHOD IdleMemoryPurge(  // do memory management already scheduled
      nsIMdbEnv* ev,           // context
      mdb_size* outEstimatedBytesFreed) =
      0;  // approximate bytes actually freed

  NS_IMETHOD SessionMemoryPurge(     // request specific footprint decrease
      nsIMdbEnv* ev,                 // context
      mdb_size inDesiredBytesFreed,  // approximate number of bytes wanted
      mdb_size* outEstimatedBytesFreed) =
      0;  // approximate bytes actually freed

  NS_IMETHOD PanicMemoryPurge(  // desperately free all possible memory
      nsIMdbEnv* ev,            // context
      mdb_size* outEstimatedBytesFreed) =
      0;  // approximate bytes actually freed
  // } ----- end memory policy methods -----

  // { ----- begin filepath methods -----
  NS_IMETHOD GetPortFilePath(
      nsIMdbEnv* ev,                   // context
      mdbYarn* outFilePath,            // name of file holding port content
      mdbYarn* outFormatVersion) = 0;  // file format description

  NS_IMETHOD GetPortFile(nsIMdbEnv* ev,  // context
                         nsIMdbFile** acqFile) =
      0;  // acquire file used by port or store
  // } ----- end filepath methods -----

  // { ----- begin export methods -----
  NS_IMETHOD BestExportFormat(         // determine preferred export format
      nsIMdbEnv* ev,                   // context
      mdbYarn* outFormatVersion) = 0;  // file format description

  // some tentative suggested import/export formats
  // "ns:msg:db:port:format:ldif:ns4.0:passthrough" // necessary
  // "ns:msg:db:port:format:ldif:ns4.5:utf8"        // necessary
  // "ns:msg:db:port:format:ldif:ns4.5:tabbed"
  // "ns:msg:db:port:format:ldif:ns4.5:binary"      // necessary
  // "ns:msg:db:port:format:html:ns3.0:addressbook" // necessary
  // "ns:msg:db:port:format:html:display:verbose"
  // "ns:msg:db:port:format:html:display:concise"
  // "ns:msg:db:port:format:mork:zany:verbose"      // necessary
  // "ns:msg:db:port:format:mork:zany:atomized"     // necessary
  // "ns:msg:db:port:format:rdf:xml"
  // "ns:msg:db:port:format:xml:mork"
  // "ns:msg:db:port:format:xml:display:verbose"
  // "ns:msg:db:port:format:xml:display:concise"
  // "ns:msg:db:port:format:xml:print:verbose"      // recommended
  // "ns:msg:db:port:format:xml:print:concise"

  NS_IMETHOD
  CanExportToFormat(  // can export content in given specific format?
      nsIMdbEnv* ev,  // context
      const char* inFormatVersion,  // file format description
      mdb_bool* outCanExport) = 0;  // whether ExportSource() might succeed

  NS_IMETHOD ExportToFormat(  // export content in given specific format
      nsIMdbEnv* ev,          // context
      // const char* inFilePath, // the file to receive exported content
      nsIMdbFile* ioFile,           // destination abstract file interface
      const char* inFormatVersion,  // file format description
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental export
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the export will be finished.

  // } ----- end export methods -----

  // { ----- begin token methods -----
  NS_IMETHOD TokenToString(        // return a string name for an integer token
      nsIMdbEnv* ev,               // context
      mdb_token inToken,           // token for inTokenName inside this port
      mdbYarn* outTokenName) = 0;  // the type of table to access

  NS_IMETHOD StringToToken(      // return an integer token for scope name
      nsIMdbEnv* ev,             // context
      const char* inTokenName,   // Latin1 string to tokenize if possible
      mdb_token* outToken) = 0;  // token for inTokenName inside this port

  // String token zero is never used and never supported. If the port
  // is a mutable store, then StringToToken() to create a new
  // association of inTokenName with a new integer token if possible.
  // But a readonly port will return zero for an unknown scope name.

  NS_IMETHOD QueryToken(         // like StringToToken(), but without adding
      nsIMdbEnv* ev,             // context
      const char* inTokenName,   // Latin1 string to tokenize if possible
      mdb_token* outToken) = 0;  // token for inTokenName inside this port

  // QueryToken() will return a string token if one already exists,
  // but unlike StringToToken(), will not assign a new token if not
  // already in use.

  // } ----- end token methods -----

  // { ----- begin row methods -----
  NS_IMETHOD HasRow(             // contains a row with the specified oid?
      nsIMdbEnv* ev,             // context
      const mdbOid* inOid,       // hypothetical row oid
      mdb_bool* outHasRow) = 0;  // whether GetRow() might succeed

  NS_IMETHOD GetRowRefCount(        // get number of tables that contain a row
      nsIMdbEnv* ev,                // context
      const mdbOid* inOid,          // hypothetical row oid
      mdb_count* outRefCount) = 0;  // number of tables containing inRowKey

  NS_IMETHOD GetRow(            // access one row with specific oid
      nsIMdbEnv* ev,            // context
      const mdbOid* inOid,      // hypothetical row oid
      nsIMdbRow** acqRow) = 0;  // acquire specific row (or null)

  // NS_IMETHOD
  // GetPortRowCursor( // get cursor for all rows in specific scope
  //   nsIMdbEnv* ev, // context
  //   mdb_scope inRowScope, // row scope for row ids
  //   nsIMdbPortRowCursor** acqCursor) = 0; // all such rows in the port

  NS_IMETHOD FindRow(
      nsIMdbEnv* ev,         // search for row with matching cell
      mdb_scope inRowScope,  // row scope for row ids
      mdb_column inColumn,   // the column to search (and maintain an index)
      const mdbYarn* inTargetCellValue,  // cell value for which to search
      mdbOid* outRowOid,        // out row oid on match (or {0,-1} for no match)
      nsIMdbRow** acqRow) = 0;  // acquire matching row (or nil for no match)
                                // can be null if you only want the oid
  // FindRow() searches for one row that has a cell in column inColumn with
  // a contained value with the same form (i.e. charset) and is byte-wise
  // identical to the blob described by yarn inTargetCellValue.  Both content
  // and form of the yarn must be an exact match to find a matching row.
  //
  // (In other words, both a yarn's blob bytes and form are significant.  The
  // form is not expected to vary in columns used for identity anyway.  This
  // is intended to make the cost of FindRow() cheaper for MDB implementors,
  // since any cell value atomization performed internally must necessarily
  // make yarn form significant in order to avoid data loss in atomization.)
  //
  // FindRow() can lazily create an index on attribute inColumn for all rows
  // with that attribute in row space scope inRowScope, so that subsequent
  // calls to FindRow() will perform faster.  Such an index might or might
  // not be persistent (but this seems desirable if it is cheap to do so).
  // Note that lazy index creation in readonly DBs is not very feasible.
  //
  // This FindRow() interface assumes that attribute inColumn is effectively
  // an alternative means of unique identification for a row in a rowspace,
  // so correct behavior is only guaranteed when no duplicates for this col
  // appear in the given set of rows.  (If more than one row has the same cell
  // value in this column, no more than one will be found; and cutting one of
  // two duplicate rows can cause the index to assume no other such row lives
  // in the row space, so future calls return nil for negative search results
  // even though some duplicate row might still live within the rowspace.)
  //
  // In other words, the FindRow() implementation is allowed to assume simple
  // hash tables mapping unique column keys to associated row values will be
  // sufficient, where any duplication is not recorded because only one copy
  // of a given key need be remembered.  Implementors are not required to sort
  // all rows by the specified column.
  // } ----- end row methods -----

  // { ----- begin table methods -----
  NS_IMETHOD HasTable(             // supports a table with the specified oid?
      nsIMdbEnv* ev,               // context
      const mdbOid* inOid,         // hypothetical table oid
      mdb_bool* outHasTable) = 0;  // whether GetTable() might succeed

  NS_IMETHOD GetTable(              // access one table with specific oid
      nsIMdbEnv* ev,                // context
      const mdbOid* inOid,          // hypothetical table oid
      nsIMdbTable** acqTable) = 0;  // acquire specific table (or null)

  NS_IMETHOD HasTableKind(       // supports a table of the specified type?
      nsIMdbEnv* ev,             // context
      mdb_scope inRowScope,      // rid scope for row ids
      mdb_kind inTableKind,      // the type of table to access
      mdb_count* outTableCount,  // current number of such tables
      mdb_bool* outSupportsTable) = 0;  // whether GetTableKind() might succeed

  // row scopes to be supported include the following suggestions:
  // "ns:msg:db:row:scope:address:cards:all"
  // "ns:msg:db:row:scope:mail:messages:all"
  // "ns:msg:db:row:scope:news:articles:all"

  // table kinds to be supported include the following suggestions:
  // "ns:msg:db:table:kind:address:cards:main"
  // "ns:msg:db:table:kind:address:lists:all"
  // "ns:msg:db:table:kind:address:list"
  // "ns:msg:db:table:kind:news:threads:all"
  // "ns:msg:db:table:kind:news:thread"
  // "ns:msg:db:table:kind:mail:threads:all"
  // "ns:msg:db:table:kind:mail:thread"

  NS_IMETHOD GetTableKind(        // access one (random) table of specific type
      nsIMdbEnv* ev,              // context
      mdb_scope inRowScope,       // row scope for row ids
      mdb_kind inTableKind,       // the type of table to access
      mdb_count* outTableCount,   // current number of such tables
      mdb_bool* outMustBeUnique,  // whether port can hold only one of these
      nsIMdbTable** acqTable) = 0;  // acquire scoped collection of rows

  NS_IMETHOD
  GetPortTableCursor(        // get cursor for all tables of specific type
      nsIMdbEnv* ev,         // context
      mdb_scope inRowScope,  // row scope for row ids
      mdb_kind inTableKind,  // the type of table to access
      nsIMdbPortTableCursor** acqCursor) = 0;  // all such tables in the port
  // } ----- end table methods -----

  // { ----- begin commit methods -----

  NS_IMETHOD ShouldCompress(        // store wastes at least inPercentWaste?
      nsIMdbEnv* ev,                // context
      mdb_percent inPercentWaste,   // 0..100 percent file size waste threshold
      mdb_percent* outActualWaste,  // 0..100 percent of file actually wasted
      mdb_bool* outShould) = 0;     // true when about inPercentWaste% is wasted
  // ShouldCompress() returns true if the store can determine that the file
  // will shrink by an estimated percentage of inPercentWaste% (or more) if
  // CompressCommit() is called, because that percentage of the file seems
  // to be recoverable free space.  The granularity is only in terms of
  // percentage points, and any value over 100 is considered equal to 100.
  //
  // If a store only has an approximate idea how much space might be saved
  // during a compress, then a best guess should be made.  For example, the
  // Mork implementation might keep track of how much file space began with
  // text content before the first updating transaction, and then consider
  // all content following the start of the first transaction as potentially
  // wasted space if it is all updates and not just new content.  (This is
  // a safe assumption in the sense that behavior will stabilize on a low
  // estimate of wastage after a commit removes all transaction updates.)
  //
  // Some db formats might attempt to keep a very accurate reckoning of free
  // space size, so a very accurate determination can be made.  But other db
  // formats might have difficulty determining size of free space, and might
  // require some lengthy calculation to answer.  This is the reason for
  // passing in the percentage threshold of interest, so that such lengthy
  // computations can terminate early as soon as at least inPercentWaste is
  // found, so that the entire file need not be groveled when unnecessary.
  // However, we hope implementations will always favor fast but imprecise
  // heuristic answers instead of extremely slow but very precise answers.
  //
  // If the outActualWaste parameter is non-nil, it will be used to return
  // the actual estimated space wasted as a percentage of file size.  (This
  // parameter is provided so callers need not call repeatedly with altered
  // inPercentWaste values to isolate the actual wastage figure.)  Note the
  // actual wastage figure returned can exactly equal inPercentWaste even
  // when this grossly underestimates the real figure involved, if the db
  // finds it very expensive to determine the extent of wastage after it is
  // known to at least exceed inPercentWaste.  Note we expect that whenever
  // outShould returns true, that outActualWaste returns >= inPercentWaste.
  //
  // The effect of different inPercentWaste values is not very uniform over
  // the permitted range.  For example, 50 represents 50% wastage, or a file
  // that is about double what it should be ideally.  But 99 represents 99%
  // wastage, or a file that is about ninety-nine times as big as it should
  // be ideally.  In the smaller direction, 25 represents 25% wastage, or
  // a file that is only 33% larger than it should be ideally.
  //
  // Callers can determine what policy they want to use for considering when
  // a file holds too much wasted space, and express this as a percentage
  // of total file size to pass as in the inPercentWaste parameter.  A zero
  // likely returns always trivially true, and 100 always trivially false.
  // The great majority of callers are expected to use values from 25 to 75,
  // since most plausible thresholds for compressing might fall between the
  // extremes of 133% of ideal size and 400% of ideal size.  (Presumably the
  // larger a file gets, the more important the percentage waste involved, so
  // a sliding scale for compress thresholds might use smaller numbers for
  // much bigger file sizes.)

  // } ----- end commit methods -----

  // } ===== end nsIMdbPort methods =====
};

/*| nsIMdbStore: a mutable interface to a specific database file.
**|
**|| tables: one can force a new table to exist in a store with NewTable()
**| and nonzero values for both row scope and table kind.  (If one wishes only
**| one table of a certain kind, then one might look for it first using the
**| GetTableKind() method).  One can pass inMustBeUnique to force future
**| users of this store to be unable to create other tables with the same pair
**| of scope and kind attributes.  When inMustBeUnique is true, and the table
**| with the given scope and kind pair already exists, then the existing one
**| is returned instead of making a new table.  Similarly, if one passes false
**| for inMustBeUnique, but the table kind has already been marked unique by a
**| previous user of the store, then the existing unique table is returned.
**|
**|| import: all or some of another port's content can be imported by calling
**| AddPortContent() with a row scope identifying the extent of content to
**| be imported.  A zero row scope will import everything.  A nonzero row
**| scope will only import tables with a matching row scope.  Note that one
**| must somehow find a way to negotiate possible conflicts between existing
**| row content and imported row content, and this involves a specific kind of
**| definition for row identity involving either row IDs or unique attributes,
**| or some combination of these two.  At the moment I am just going to wave
**| my hands, and say the default behavior is to assign all new row identities
**| to all imported content, which will result in no merging of content; this
**| must change later because it is unacceptable in some contexts.
**|
**|| commits: to manage modifications in a mutable store, very few methods are
**| really needed to indicate global policy choices that are independent of
**| the actual modifications that happen in objects at the level of tables,
**| rows, and cells, etc.  The most important policy to specify is which sets
**| of changes are considered associated in a manner such that they should be
**| applied together atomically to a given store.  We call each such group of
**| changes a transaction.  We handle three different grades of transaction,
**| but they differ only in semantic significance to the application, and are
**| not intended to nest.  (If small transactions were nested inside large
**| transactions, that would imply that a single large transaction must be
**| atomic over all the contained small transactions; but actually we intend
**| smalls transaction never be undone once committed due to, say, aborting a
**| transaction of greater significance.)  The small, large, and session level
**| commits have equal granularity, and differ only in risk of loss from the
**| perspective of an application.  Small commits characterize changes that
**| can be lost with relatively small risk, so small transactions can delay
**| until later if they are expensive or impractical to commit.  Large commits
**| involve changes that would probably inconvenience users if lost, so the
**| need to pay costs of writing is rather greater than with small commits.
**| Session commits are last ditch attempts to save outstanding changes before
**| stopping the use of a particular database, so there will be no later point
**| in time to save changes that have been delayed due to possible high cost.
**| If large commits are never delayed, then a session commit has about the
**| same performance effect as another large commit; but if small and large
**| commits are always delayed, then a session commit is likely to be rather
**| expensive as a runtime cost compared to any earlier database usage.
**|
**|| aborts: the only way to abort changes to a store is by closing the store.
**| So there is no specific method for causing any abort.  Stores must discard
**| all changes made that are uncommitted when a store is closed.  This design
**| choice makes the implementations of tables, rows, and cells much less
**| complex because they need not maintain a record of undobable changes.  When
**| a store is closed, presumably this precipitates the closure of all tables,
**| rows, and cells in the store as well.   So an application can revert the
**| state of a store in the user interface by quietly closing and reopening a
**| store, because this will discard uncommitted changes and show old content.
**| This implies an app that closes a store will need to send a "scramble"
**| event notification to any views that depend on old discarded content.
|*/

#define NS_IMDBSTORE_IID_STR "74d6218d-44b0-43b5-9ebe-69a17dfb562c"
#define NS_IMDBSTORE_IID                             \
  {                                                  \
    0x74d6218d, 0x44b0, 0x43b5, {                    \
      0x9e, 0xbe, 0x69, 0xa1, 0x7d, 0xfb, 0x56, 0x2c \
    }                                                \
  }

class nsIMdbStore : public nsIMdbPort {
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBSTORE_IID)

  // { ===== begin nsIMdbStore methods =====

  // { ----- begin table methods -----
  NS_IMETHOD NewTable(          // make one new table of specific type
      nsIMdbEnv* ev,            // context
      mdb_scope inRowScope,     // row scope for row ids
      mdb_kind inTableKind,     // the type of table to access
      mdb_bool inMustBeUnique,  // whether store can hold only one of these
      const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
      nsIMdbTable** acqTable) = 0;         // acquire scoped collection of rows

  NS_IMETHOD NewTableWithOid(   // make one new table of specific type
      nsIMdbEnv* ev,            // context
      const mdbOid* inOid,      // caller assigned oid
      mdb_kind inTableKind,     // the type of table to access
      mdb_bool inMustBeUnique,  // whether store can hold only one of these
      const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
      nsIMdbTable** acqTable) = 0;         // acquire scoped collection of rows
  // } ----- end table methods -----

  // { ----- begin row scope methods -----
  NS_IMETHOD RowScopeHasAssignedIds(
      nsIMdbEnv* ev,
      mdb_scope inRowScope,         // row scope for row ids
      mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
      mdb_bool* outStoreAssigned) =
      0;  // nonzero if store db assigned specified

  NS_IMETHOD SetCallerAssignedIds(
      nsIMdbEnv* ev,
      mdb_scope inRowScope,         // row scope for row ids
      mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
      mdb_bool* outStoreAssigned) =
      0;  // nonzero if store db assigned specified

  NS_IMETHOD SetStoreAssignedIds(
      nsIMdbEnv* ev,
      mdb_scope inRowScope,         // row scope for row ids
      mdb_bool* outCallerAssigned,  // nonzero if caller assigned specified
      mdb_bool* outStoreAssigned) =
      0;  // nonzero if store db assigned specified
  // } ----- end row scope methods -----

  // { ----- begin row methods -----
  NS_IMETHOD NewRowWithOid(nsIMdbEnv* ev,  // new row w/ caller assigned oid
                           const mdbOid* inOid,      // caller assigned oid
                           nsIMdbRow** acqRow) = 0;  // create new row

  NS_IMETHOD NewRow(nsIMdbEnv* ev,            // new row with db assigned oid
                    mdb_scope inRowScope,     // row scope for row ids
                    nsIMdbRow** acqRow) = 0;  // create new row
  // Note this row must be added to some table or cell child before the
  // store is closed in order to make this row persist across sessions.

  // } ----- end row methods -----

  // { ----- begin inport/export methods -----
  NS_IMETHOD ImportContent(         // import content from port
      nsIMdbEnv* ev,                // context
      mdb_scope inRowScope,         // scope for rows (or zero for all?)
      nsIMdbPort* ioPort,           // the port with content to add to store
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental import
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the import will be finished.

  NS_IMETHOD ImportFile(            // import content from port
      nsIMdbEnv* ev,                // context
      nsIMdbFile* ioFile,           // the file with content to add to store
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental import
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the import will be finished.
  // } ----- end inport/export methods -----

  // { ----- begin hinting methods -----
  NS_IMETHOD
  ShareAtomColumnsHint(       // advise re shared column content atomizing
      nsIMdbEnv* ev,          // context
      mdb_scope inScopeHint,  // zero, or suggested shared namespace
      const mdbColumnSet* inColumnSet) = 0;  // cols desired tokenized together

  NS_IMETHOD
  AvoidAtomColumnsHint(  // advise column with poor atomizing prospects
      nsIMdbEnv* ev,     // context
      const mdbColumnSet* inColumnSet) =
      0;  // cols with poor atomizing prospects
  // } ----- end hinting methods -----

  // { ----- begin commit methods -----
  NS_IMETHOD LargeCommit(           // save important changes if at all possible
      nsIMdbEnv* ev,                // context
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental commit
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the commit will be finished.  Note the store is effectively write
  // locked until commit is finished or canceled through the thumb instance.
  // Until the commit is done, the store will report it has readonly status.

  NS_IMETHOD SessionCommit(         // save all changes if large commits delayed
      nsIMdbEnv* ev,                // context
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental commit
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the commit will be finished.  Note the store is effectively write
  // locked until commit is finished or canceled through the thumb instance.
  // Until the commit is done, the store will report it has readonly status.

  NS_IMETHOD
  CompressCommit(     // commit and make db physically smaller if possible
      nsIMdbEnv* ev,  // context
      nsIMdbThumb** acqThumb) = 0;  // acquire thumb for incremental commit
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the commit will be finished.  Note the store is effectively write
  // locked until commit is finished or canceled through the thumb instance.
  // Until the commit is done, the store will report it has readonly status.

  // } ----- end commit methods -----

  // } ===== end nsIMdbStore methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbStore, NS_IMDBSTORE_IID)

/*| nsIMdbCursor: base cursor class for iterating row cells and table rows
**|
**|| count: the number of elements in the collection (table or row)
**|
**|| seed: the change count in the underlying collection, which is synced
**| with the collection when the iteration position is set, and henceforth
**| acts to show whether the iter has lost collection synchronization, in
**| case it matters to clients whether any change happens during iteration.
**|
**|| pos: the position of the current element in the collection.  Negative
**| means a position logically before the first element.  A positive value
**| equal to count (or larger) implies a position after the last element.
**| To iterate over all elements, set the position to negative, so subsequent
**| calls to any 'next' method will access the first collection element.
**|
**|| doFailOnSeedOutOfSync: whether a cursor should return an error if the
**| cursor's snapshot of a table's seed becomes stale with respect the table's
**| current seed value (which implies the iteration is less than total) in
**| between to cursor calls that actually access collection content.  By
**| default, a cursor should assume this attribute is false until specified,
**| so that iterations quietly try to re-sync when they lose coherence.
|*/

#define NS_IMDBCURSOR_IID_STR "a0c37337-6ebc-474c-90db-e65ea0b850aa"

#define NS_IMDBCURSOR_IID                            \
  {                                                  \
    0xa0c37337, 0x6ebc, 0x474c, {                    \
      0x90, 0xdb, 0xe6, 0x5e, 0xa0, 0xb8, 0x50, 0xaa \
    }                                                \
  }

class nsIMdbCursor : public nsISupports {  // collection iterator
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBCURSOR_IID)
  // { ===== begin nsIMdbCursor methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD GetCount(nsIMdbEnv* ev, mdb_count* outCount) = 0;  // readonly
  NS_IMETHOD GetSeed(nsIMdbEnv* ev, mdb_seed* outSeed) = 0;     // readonly

  NS_IMETHOD SetPos(nsIMdbEnv* ev, mdb_pos inPos) = 0;  // mutable
  NS_IMETHOD GetPos(nsIMdbEnv* ev, mdb_pos* outPos) = 0;

  NS_IMETHOD SetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool inFail) = 0;
  NS_IMETHOD GetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool* outFail) = 0;
  // } ----- end attribute methods -----

  // } ===== end nsIMdbCursor methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCursor, NS_IMDBCURSOR_IID)

#define NS_IMDBPORTTABLECURSOR_IID_STR = "f181a41e-933d-49b3-af93-20d3634b8b78"

#define NS_IMDBPORTTABLECURSOR_IID                   \
  {                                                  \
    0xf181a41e, 0x933d, 0x49b3, {                    \
      0xaf, 0x93, 0x20, 0xd3, 0x63, 0x4b, 0x8b, 0x78 \
    }                                                \
  }

/*| nsIMdbPortTableCursor: cursor class for iterating port tables
**|
**|| port: the cursor is associated with a specific port, which can be
**| set to a different port (which resets the position to -1 so the
**| next table acquired is the first in the port.
**|
|*/
class nsIMdbPortTableCursor : public nsISupports {  // table collection iterator
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBPORTTABLECURSOR_IID)
  // { ===== begin nsIMdbPortTableCursor methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD SetPort(nsIMdbEnv* ev, nsIMdbPort* ioPort) = 0;  // sets pos to -1
  NS_IMETHOD GetPort(nsIMdbEnv* ev, nsIMdbPort** acqPort) = 0;

  NS_IMETHOD SetRowScope(nsIMdbEnv* ev,  // sets pos to -1
                         mdb_scope inRowScope) = 0;
  NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
  // setting row scope to zero iterates over all row scopes in port

  NS_IMETHOD SetTableKind(nsIMdbEnv* ev,  // sets pos to -1
                          mdb_kind inTableKind) = 0;
  NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
  // setting table kind to zero iterates over all table kinds in row scope
  // } ----- end attribute methods -----

  // { ----- begin table iteration methods -----
  NS_IMETHOD NextTable(             // get table at next position in the db
      nsIMdbEnv* ev,                // context
      nsIMdbTable** acqTable) = 0;  // the next table in the iteration
  // } ----- end table iteration methods -----

  // } ===== end nsIMdbPortTableCursor methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbPortTableCursor, NS_IMDBPORTTABLECURSOR_IID)

/*| nsIMdbCollection: an object that collects a set of other objects as members.
**| The main purpose of this base class is to unify the perceived semantics
**| of tables and rows where their collection behavior is similar.  This helps
**| isolate the mechanics of collection behavior from the other semantics that
**| are more characteristic of rows and tables.
**|
**|| count: the number of objects in a collection is the member count. (Some
**| collection interfaces call this attribute the 'size', but that can be a
**| little ambiguous, and counting actual members is harder to confuse.)
**|
**|| seed: the seed of a collection is a counter for changes in membership in
**| a specific collection.  This seed should change when members are added to
**| or removed from a collection, but not when a member changes internal state.
**| The seed should also change whenever the internal collection of members has
**| a complex state change that reorders member positions (say by sorting) that
**| would affect the nature of an iteration over that collection of members.
**| The purpose of a seed is to inform any outstanding collection cursors that
**| they might be stale, without incurring the cost of broadcasting an event
**| notification to such cursors, which would need more data structure support.
**| Presumably a cursor in a particular mdb code suite has much more direct
**| access to a collection seed member slot that this abstract COM interface,
**| so this information is intended more for clients outside mdb that want to
**| make inferences similar to those made by the collection cursors.  The seed
**| value as an integer magnitude is not very important, and callers should not
**| assume meaningful information can be derived from an integer value beyond
**| whether it is equal or different from a previous inspection.  A seed uses
**| integers of many bits in order to make the odds of wrapping and becoming
**| equal to an earlier seed value have probability that is vanishingly small.
**|
**|| port: every collection is associated with a specific database instance.
**|
**|| cursor: a subclass of nsIMdbCursor suitable for this specific collection
**| subclass.  The ability to GetCursor() from the base nsIMdbCollection class
**| is not really as useful as getting a more specifically typed cursor more
**| directly from the base class without any casting involved.  So including
**| this method here is more for conceptual illustration.
**|
**|| oid: every collection has an identity that persists from session to
**| session. Implementations are probably able to distinguish row IDs from
**| table IDs, but we don't specify anything official in this regard.  A
**| collection has the same identity for the lifetime of the collection,
**| unless identity is swapped with another collection by means of a call to
**| BecomeContent(), which is considered a way to swap a new representation
**| for an old well-known object.  (Even so, only content appears to change,
**| while the identity seems to stay the same.)
**|
**|| become: developers can effectively cause two objects to swap identities,
**| in order to effect a complete swap between what persistent content is
**| represented by two oids.  The caller should consider this a content swap,
**| and not identity wap, because identities will seem to stay the same while
**| only content changes.  However, implementations will likely do this
**| internally by swapping identities.  Callers must swap content only
**| between objects of similar type, such as a row with another row, and a
**| table with another table, because implementations need not support
**| cross-object swapping because it might break object name spaces.
**|
**|| dropping: when a caller expects a row or table will no longer be used, the
**| caller can tell the collection to 'drop activity', which means the runtime
**| object can have its internal representation purged to save memory or any
**| other resource that is being consumed by the collection's representation.
**| This has no effect on the collection's persistent content or semantics,
**| and is only considered a runtime effect.  After a collection drops
**| activity, the object should still be as usable as before (because it has
**| NOT been closed), but further usage can be expensive to re-instate because
**| it might involve reallocating space and/or re-reading disk space.  But
**| since this future usage is not expected, the caller does not expect to
**| pay the extra expense.  An implementation can choose to implement
**| 'dropping activity' in different ways, or even not at all if this
**| operation is not really feasible.  Callers cannot ask objects whether they
**| are 'dropped' or not, so this should be transparent. (Note that
**| implementors might fear callers do not really know whether future
**| usage will occur, and therefore might delay the act of dropping until
**| the near future, until seeing whether the object is used again
**| immediately elsewhere. Such use soon after the drop request might cause
**| the drop to be cancelled.)
|*/
class nsIMdbCollection : public nsISupports {  // sequence of objects
 public:
  // { ===== begin nsIMdbCollection methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD GetSeed(nsIMdbEnv* ev,
                     mdb_seed* outSeed) = 0;  // member change count
  NS_IMETHOD GetCount(nsIMdbEnv* ev,
                      mdb_count* outCount) = 0;  // member count

  NS_IMETHOD GetPort(nsIMdbEnv* ev,
                     nsIMdbPort** acqPort) = 0;  // collection container
  // } ----- end attribute methods -----

  // { ----- begin cursor methods -----
  NS_IMETHOD GetCursor(     // make a cursor starting iter at inMemberPos
      nsIMdbEnv* ev,        // context
      mdb_pos inMemberPos,  // zero-based ordinal pos of member in collection
      nsIMdbCursor** acqCursor) = 0;  // acquire new cursor instance
  // } ----- end cursor methods -----

  // { ----- begin ID methods -----
  NS_IMETHOD GetOid(nsIMdbEnv* ev,
                    mdbOid* outOid) = 0;  // read object identity
  NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
                           const mdbOid* inOid) = 0;  // exchange content
  // } ----- end ID methods -----

  // { ----- begin activity dropping methods -----
  NS_IMETHOD DropActivity(  // tell collection usage no longer expected
      nsIMdbEnv* ev) = 0;
  // } ----- end activity dropping methods -----

  // } ===== end nsIMdbCollection methods =====
};

/*| nsIMdbTable: an ordered collection of rows
**|
**|| row scope: an integer token for an atomized string in this database
**| that names a space for row IDs.  This attribute of a table is intended
**| as guidance metainformation that helps with searching a database for
**| tables that operate on collections of rows of the specific type.  By
**| convention, a table with a specific row scope is expected to focus on
**| containing rows that belong to that scope, however exceptions are easily
**| allowed because all rows in a table are known by both row ID and scope.
**| (A table with zero row scope is never allowed because this would make it
**| ambiguous to use a zero row scope when iterating over tables in a port to
**| indicate that all row scopes should be seen by a cursor.)
**|
**|| table kind: an integer token for an atomized string in this database
**| that names a kind of table as a subset of the associated row scope. This
**| attribute is intended as guidance metainformation to clarify the role of
**| this table with respect to other tables in the same row scope, and this
**| also helps search for such tables in a database.  By convention, a table
**| with a specific table kind has a consistent role for containing rows with
**| respect to other collections of such rows in the same row scope.  Also by
**| convention, at least one table in a row scope has a table kind purporting
**| to contain ALL the rows that belong in that row scope, so that at least
**| one table exists that allows all rows in a scope to be interated over.
**| (A table with zero table kind is never allowed because this would make it
**| ambiguous to use a zero table kind when iterating over tables in a port to
**| indicate that all table kinds in a row scope should be seen by a cursor.)
**|
**|| port: every table is considered part of some port that contains the
**| table, so that closing the containing port will cause the table to be
**| indirectly closed as well.  We make it easy to get the containing port for
**| a table, because the port supports important semantic interfaces that will
**| affect how content in table is presented; the most important port context
**| that affects a table is specified by the set of token to string mappings
**| that affect all tokens used throughout the database, and which drive the
**| meanings of row scope, table kind, cell columns, etc.
**|
**|| cursor: a cursor that iterates over the rows in this table, where rows
**| have zero-based index positions from zero to count-1.  Making a cursor
**| with negative position will next iterate over the first row in the table.
**|
**|| position: given any position from zero to count-1, a table will return
**| the row ID and row scope for the row at that position.  (One can use the
**| GetRowAllCells() method to read that row, or else use a row cursor to both
**| get the row at some position and read its content at the same time.)  The
**| position depends on whether a table is sorted, and upon the actual sort.
**| Note that moving a row's position is only possible in unsorted tables.
**|
**|| row set: every table contains a collection of rows, where a member row is
**| referenced by the table using the row ID and row scope for the row.  No
**| single table owns a given row instance, because rows are effectively ref-
**| counted and destroyed only when the last table removes a reference to that
**| particular row.  (But a row can be emptied of all content no matter how
**| many refs exist, and this might be the next best thing to destruction.)
**| Once a row exists in a least one table (after NewRow() is called), then it
**| can be added to any other table by calling AddRow(), or removed from any
**| table by calling CutRow(), or queried as a member by calling HasRow().  A
**| row can only be added to a table once, and further additions do nothing and
**| complain not at all.  Cutting a row from a table only does something when
**| the row was actually a member, and otherwise does nothing silently.
**|
**|| row ref count: one can query the number of tables (and/or cells)
**| containing a row as a member or a child.
**|
**|| row content: one can access or modify the cell content in a table's row
**| by moving content to or from an instance of nsIMdbRow.  Note that nsIMdbRow
**| never represents the actual row inside a table, and this is the reason
**| why nsIMdbRow instances do not have row IDs or row scopes.  So an instance
**| of nsIMdbRow always and only contains a snapshot of some or all content in
**| past, present, or future persistent row inside a table.  This means that
**| reading and writing rows in tables has strictly copy semantics, and we
**| currently do not plan any exceptions for specific performance reasons.
**|
**|| sorting: note all rows are assumed sorted by row ID as a secondary
**| sort following the primary column sort, when table rows are sorted.
**|
**|| indexes:
|*/

#define NS_IMDBTABLE_IID_STR = "fe11bc98-d02b-4128-9fac-87042fdf9639"

#define NS_IMDBTABLE_IID                             \
  {                                                  \
    0xfe11bc98, 0xd02b, 0x4128, {                    \
      0x9f, 0xac, 0x87, 0x04, 0x2f, 0xdf, 0x96, 0x39 \
    }                                                \
  }

class nsIMdbTable : public nsIMdbCollection {  // a collection of rows
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLE_IID)
  // { ===== begin nsIMdbTable methods =====

  // { ----- begin meta attribute methods -----
  NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) = 0;
  NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) = 0;

  NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) = 0;
  NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) = 0;

  NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) = 0;

  NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
  NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;

  NS_IMETHOD GetMetaRow(
      nsIMdbEnv* ev,                       // context
      const mdbOid* inOptionalMetaRowOid,  // can be nil to avoid specifying
      mdbOid* outOid,  // output meta row oid, can be nil to suppress output
      nsIMdbRow** acqRow) = 0;  // acquire table's unique singleton meta row
  // The purpose of a meta row is to support the persistent recording of
  // meta info about a table as cells put into the distinguished meta row.
  // Each table has exactly one meta row, which is not considered a member
  // of the collection of rows inside the table.  The only way to tell
  // whether a row is a meta row is by the fact that it is returned by this
  // GetMetaRow() method from some table. Otherwise nothing distinguishes
  // a meta row from any other row.  A meta row can be used anyplace that
  // any other row can be used, and can even be put into other tables (or
  // the same table) as a table member, if this is useful for some reason.
  // The first attempt to access a table's meta row using GetMetaRow() will
  // cause the meta row to be created if it did not already exist.  When the
  // meta row is created, it will have the row oid that was previously
  // requested for this table's meta row; or if no oid was ever explicitly
  // specified for this meta row, then a unique oid will be generated in
  // the row scope named "m" (so obviously MDB clients should not
  // manually allocate any row IDs from that special meta scope namespace).
  // The meta row oid can be specified either when the table is created, or
  // else the first time that GetMetaRow() is called, by passing a non-nil
  // pointer to an oid for parameter inOptionalMetaRowOid.  The meta row's
  // actual oid is returned in outOid (if this is a non-nil pointer), and
  // it will be different from inOptionalMetaRowOid when the meta row was
  // already given a different oid earlier.
  // } ----- end meta attribute methods -----

  // { ----- begin cursor methods -----
  NS_IMETHOD
  GetTableRowCursor(     // make a cursor, starting iteration at inRowPos
      nsIMdbEnv* ev,     // context
      mdb_pos inRowPos,  // zero-based ordinal position of row in table
      nsIMdbTableRowCursor** acqCursor) = 0;  // acquire new cursor instance
  // } ----- end row position methods -----

  // { ----- begin row position methods -----
  NS_IMETHOD PosToOid(      // get row member for a table position
      nsIMdbEnv* ev,        // context
      mdb_pos inRowPos,     // zero-based ordinal position of row in table
      mdbOid* outOid) = 0;  // row oid at the specified position

  NS_IMETHOD OidToPos(       // test for the table position of a row member
      nsIMdbEnv* ev,         // context
      const mdbOid* inOid,   // row to find in table
      mdb_pos* outPos) = 0;  // zero-based ordinal position of row in table

  NS_IMETHOD PosToRow(          // test for the table position of a row member
      nsIMdbEnv* ev,            // context
      mdb_pos inRowPos,         // zero-based ordinal position of row in table
      nsIMdbRow** acqRow) = 0;  // acquire row at table position inRowPos

  NS_IMETHOD RowToPos(       // test for the table position of a row member
      nsIMdbEnv* ev,         // context
      nsIMdbRow* ioRow,      // row to find in table
      mdb_pos* outPos) = 0;  // zero-based ordinal position of row in table
  // } ----- end row position methods -----

  // { ----- begin oid set methods -----
  NS_IMETHOD AddOid(  // make sure the row with inOid is a table member
      nsIMdbEnv* ev,  // context
      const mdbOid* inOid) = 0;  // row to ensure membership in table

  NS_IMETHOD HasOid(             // test for the table position of a row member
      nsIMdbEnv* ev,             // context
      const mdbOid* inOid,       // row to find in table
      mdb_bool* outHasOid) = 0;  // whether inOid is a member row

  NS_IMETHOD CutOid(             // make sure the row with inOid is not a member
      nsIMdbEnv* ev,             // context
      const mdbOid* inOid) = 0;  // row to remove from table
  // } ----- end oid set methods -----

  // { ----- begin row set methods -----
  NS_IMETHOD NewRow(  // create a new row instance in table
      nsIMdbEnv* ev,  // context
      mdbOid*
          ioOid,  // please use minus one (unbound) rowId for db-assigned IDs
      nsIMdbRow** acqRow) = 0;  // create new row

  NS_IMETHOD AddRow(          // make sure the row with inOid is a table member
      nsIMdbEnv* ev,          // context
      nsIMdbRow* ioRow) = 0;  // row to ensure membership in table

  NS_IMETHOD HasRow(             // test for the table position of a row member
      nsIMdbEnv* ev,             // context
      nsIMdbRow* ioRow,          // row to find in table
      mdb_bool* outHasRow) = 0;  // whether row is a table member

  NS_IMETHOD CutRow(          // make sure the row with inOid is not a member
      nsIMdbEnv* ev,          // context
      nsIMdbRow* ioRow) = 0;  // row to remove from table

  NS_IMETHOD CutAllRows(   // remove all rows from the table
      nsIMdbEnv* ev) = 0;  // context
  // } ----- end row set methods -----

  // { ----- begin hinting methods -----
  NS_IMETHOD SearchColumnsHint(  // advise re future expected search cols
      nsIMdbEnv* ev,             // context
      const mdbColumnSet* inColumnSet) = 0;  // columns likely to be searched

  NS_IMETHOD SortColumnsHint(  // advise re future expected sort columns
      nsIMdbEnv* ev,           // context
      const mdbColumnSet* inColumnSet) = 0;  // columns for likely sort requests

  NS_IMETHOD StartBatchChangeHint(  // advise before many adds and cuts
      nsIMdbEnv* ev,                // context
      const void* inLabel) = 0;     // intend unique address to match end call
  // If batch starts nest by virtue of nesting calls in the stack, then
  // the address of a local variable makes a good batch start label that
  // can be used at batch end time, and such addresses remain unique.

  NS_IMETHOD EndBatchChangeHint(  // advise before many adds and cuts
      nsIMdbEnv* ev,              // context
      const void* inLabel) = 0;   // label matching start label
  // Suppose a table is maintaining one or many sort orders for a table,
  // so that every row added to the table must be inserted in each sort,
  // and every row cut must be removed from each sort.  If a db client
  // intends to make many such changes before needing any information
  // about the order or positions of rows inside a table, then a client
  // might tell the table to start batch changes in order to disable
  // sorting of rows for the interim.  Presumably a table will then do
  // a full sort of all rows at need when the batch changes end, or when
  // a surprise request occurs for row position during batch changes.
  // } ----- end hinting methods -----

  // { ----- begin searching methods -----
  NS_IMETHOD FindRowMatches(  // search variable number of sorted cols
      nsIMdbEnv* ev,          // context
      const mdbYarn*
          inPrefix,  // content to find as prefix in row's column cell
      nsIMdbTableRowCursor** acqCursor) = 0;  // set of matching rows

  NS_IMETHOD GetSearchColumns(       // query columns used by FindRowMatches()
      nsIMdbEnv* ev,                 // context
      mdb_count* outCount,           // context
      mdbColumnSet* outColSet) = 0;  // caller supplied space to put columns
  // GetSearchColumns() returns the columns actually searched when the
  // FindRowMatches() method is called.  No more than mColumnSet_Count
  // slots of mColumnSet_Columns will be written, since mColumnSet_Count
  // indicates how many slots are present in the column array.  The
  // actual number of search column used by the table is returned in
  // the outCount parameter; if this number exceeds mColumnSet_Count,
  // then a caller needs a bigger array to read the entire column set.
  // The minimum of mColumnSet_Count and outCount is the number slots
  // in mColumnSet_Columns that were actually written by this method.
  //
  // Callers are expected to change this set of columns by calls to
  // nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
  // } ----- end searching methods -----

  // { ----- begin sorting methods -----
  // sorting: note all rows are assumed sorted by row ID as a secondary
  // sort following the primary column sort, when table rows are sorted.

  NS_IMETHOD
  CanSortColumn(            // query which column is currently used for sorting
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // column to query sorting potential
      mdb_bool* outCanSort) = 0;  // whether the column can be sorted

  NS_IMETHOD GetSorting(    // view same table in particular sorting
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // requested new column for sorting table
      nsIMdbSorting** acqSorting) = 0;  // acquire sorting for column

  NS_IMETHOD SetSearchSorting(  // use this sorting in FindRowMatches()
      nsIMdbEnv* ev,            // context
      mdb_column inColumn,      // often same as nsIMdbSorting::GetSortColumn()
      nsIMdbSorting* ioSorting) = 0;  // requested sorting for some column
  // SetSearchSorting() attempts to inform the table that ioSorting
  // should be used during calls to FindRowMatches() for searching
  // the column which is actually sorted by ioSorting.  This method
  // is most useful in conjunction with nsIMdbSorting::SetCompare(),
  // because otherwise a caller would not be able to override the
  // comparison ordering method used during searches.  Note that some
  // database implementations might be unable to use an arbitrarily
  // specified sort order, either due to schema or runtime interface
  // constraints, in which case ioSorting might not actually be used.
  // Presumably ioSorting is an instance that was returned from some
  // earlier call to nsIMdbTable::GetSorting().  A caller can also
  // use nsIMdbTable::SearchColumnsHint() to specify desired change
  // in which columns are sorted and searched by FindRowMatches().
  //
  // A caller can pass a nil pointer for ioSorting to request that
  // column inColumn no longer be used at all by FindRowMatches().
  // But when ioSorting is non-nil, then inColumn should match the
  // column actually sorted by ioSorting; when these do not agree,
  // implementations are instructed to give precedence to the column
  // specified by ioSorting (so this means callers might just pass
  // zero for inColumn when ioSorting is also provided, since then
  // inColumn is both redundant and ignored).
  // } ----- end sorting methods -----

  // { ----- begin moving methods -----
  // moving a row does nothing unless a table is currently unsorted

  NS_IMETHOD MoveOid(              // change position of row in unsorted table
      nsIMdbEnv* ev,               // context
      const mdbOid* inOid,         // row oid to find in table
      mdb_pos inHintFromPos,       // suggested hint regarding start position
      mdb_pos inToPos,             // desired new position for row inRowId
      mdb_pos* outActualPos) = 0;  // actual new position of row in table

  NS_IMETHOD MoveRow(              // change position of row in unsorted table
      nsIMdbEnv* ev,               // context
      nsIMdbRow* ioRow,            // row oid to find in table
      mdb_pos inHintFromPos,       // suggested hint regarding start position
      mdb_pos inToPos,             // desired new position for row inRowId
      mdb_pos* outActualPos) = 0;  // actual new position of row in table
  // } ----- end moving methods -----

  // { ----- begin index methods -----
  NS_IMETHOD AddIndex(      // create a sorting index for column if possible
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // the column to sort by index
      nsIMdbThumb** acqThumb) =
      0;  // acquire thumb for incremental index building
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the index addition will be finished.

  NS_IMETHOD CutIndex(      // stop supporting a specific column index
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // the column with index to be removed
      nsIMdbThumb** acqThumb) =
      0;  // acquire thumb for incremental index destroy
  // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
  // then the index removal will be finished.

  NS_IMETHOD HasIndex(      // query for current presence of a column index
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // the column to investigate
      mdb_bool* outHasIndex) = 0;  // whether column has index for this column

  NS_IMETHOD EnableIndexOnSort(  // create an index for col on first sort
      nsIMdbEnv* ev,             // context
      mdb_column inColumn) = 0;  // the column to index if ever sorted

  NS_IMETHOD QueryIndexOnSort(  // check whether index on sort is enabled
      nsIMdbEnv* ev,            // context
      mdb_column inColumn,      // the column to investigate
      mdb_bool* outIndexOnSort) =
      0;  // whether column has index-on-sort enabled

  NS_IMETHOD DisableIndexOnSort(  // prevent future index creation on sort
      nsIMdbEnv* ev,              // context
      mdb_column inColumn) = 0;   // the column to index if ever sorted
  // } ----- end index methods -----

  // } ===== end nsIMdbTable methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTable, NS_IMDBTABLE_IID)

/*| nsIMdbSorting: a view of a table in some particular sort order.  This
**| row order closely resembles a readonly array of rows with the same row
**| membership as the underlying table, but in a different order than the
**| table's explicit row order.  But the sorting's row membership changes
**| whenever the table's membership changes (without any notification, so
**| keep this in mind when modifying the table).
**|
**|| table: every sorting is associated with a particular table.  You
**| cannot change which table is used by a sorting (just ask some new
**| table for a suitable sorting instance instead).
**|
**|| compare: the ordering method used by a sorting, wrapped up in a
**| abstract plug-in interface.  When this was never installed by an
**| explicit call to SetNewCompare(), a compare object is still returned,
**| and it might match the compare instance returned by the factory method
**| nsIMdbFactory::MakeCompare(), which represents a default sort order
**| (which we fervently hope is consistently ASCII byte ordering).
**|
**|| cursor: in case callers are more comfortable with a cursor style
**| of accessing row members, each sorting will happily return a cursor
**| instance with behavior very similar to a cursor returned from a call
**| to nsIMdbTable::GetTableRowCursor(), but with different row order.
**| A cursor should show exactly the same information as the pos methods.
**|
**|| pos: the PosToOid() and PosToRow() methods are just like the table
**| methods of the same name, except they show rows in the sort order of
**| the sorting, rather than that of the table.  These methods are like
**| readonly array position accessor's, or like a C++ operator[].
|*/
class nsIMdbSorting : public nsIMdbObject {  // sorting of some table
 public:
  // { ===== begin nsIMdbSorting methods =====

  // { ----- begin attribute methods -----
  // sorting: note all rows are assumed sorted by row ID as a secondary
  // sort following the primary column sort, when table rows are sorted.

  NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable) = 0;
  NS_IMETHOD GetSortColumn(        // query which col is currently sorted
      nsIMdbEnv* ev,               // context
      mdb_column* outColumn) = 0;  // col the table uses for sorting (or zero)

  // } ----- end attribute methods -----

  // { ----- begin cursor methods -----
  NS_IMETHOD GetSortingRowCursor(  // make a cursor, starting at inRowPos
      nsIMdbEnv* ev,               // context
      mdb_pos inRowPos,  // zero-based ordinal position of row in table
      nsIMdbTableRowCursor** acqCursor) = 0;  // acquire new cursor instance
  // A cursor interface turning same info as PosToOid() or PosToRow().
  // } ----- end row position methods -----

  // { ----- begin row position methods -----
  NS_IMETHOD PosToOid(      // get row member for a table position
      nsIMdbEnv* ev,        // context
      mdb_pos inRowPos,     // zero-based ordinal position of row in table
      mdbOid* outOid) = 0;  // row oid at the specified position

  NS_IMETHOD PosToRow(          // test for the table position of a row member
      nsIMdbEnv* ev,            // context
      mdb_pos inRowPos,         // zero-based ordinal position of row in table
      nsIMdbRow** acqRow) = 0;  // acquire row at table position inRowPos
  // } ----- end row position methods -----

  // } ===== end nsIMdbSorting methods =====
};

/*| nsIMdbTableRowCursor: cursor class for iterating table rows
**|
**|| table: the cursor is associated with a specific table, which can be
**| set to a different table (which resets the position to -1 so the
**| next row acquired is the first in the table.
**|
**|| NextRowId: the rows in the table can be iterated by identity alone,
**| without actually reading the cells of any row with this method.
**|
**|| NextRowCells: read the next row in the table, but only read cells
**| from the table which are already present in the row (so no new cells
**| are added to the row, even if they are present in the table).  All the
**| cells will have content specified, even it is the empty string.  No
**| columns will be removed, even if missing from the row (because missing
**| and empty are semantically equivalent).
**|
**|| NextRowAllCells: read the next row in the table, and access all the
**| cells for this row in the table, adding any missing columns to the row
**| as needed until all cells are represented.  All the
**| cells will have content specified, even it is the empty string.  No
**| columns will be removed, even if missing from the row (because missing
**| and empty are semantically equivalent).
**|
|*/

#define NS_IMDBTABLEROWCURSOR_IID_STR = "4f325dad-0385-4b62-a992-c914ab93587e"

#define NS_IMDBTABLEROWCURSOR_IID                    \
  {                                                  \
    0x4f325dad, 0x0385, 0x4b62, {                    \
      0xa9, 0x92, 0xc9, 0x14, 0xab, 0x93, 0x58, 0x7e \
    }                                                \
  }

class nsIMdbTableRowCursor : public nsISupports {  // table row iterator
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLEROWCURSOR_IID)

  // { ===== begin nsIMdbTableRowCursor methods =====

  // { ----- begin attribute methods -----
  // NS_IMETHOD SetTable(nsIMdbEnv* ev, nsIMdbTable* ioTable) = 0; // sets pos
  // to -1 Method SetTable() cut and made obsolete in keeping with new sorting
  // methods.

  NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable) = 0;
  // } ----- end attribute methods -----

  // { ----- begin duplicate row removal methods -----
  NS_IMETHOD CanHaveDupRowMembers(nsIMdbEnv* ev,  // cursor might hold dups?
                                  mdb_bool* outCanHaveDups) = 0;

  NS_IMETHOD MakeUniqueCursor(  // clone cursor, removing duplicate rows
      nsIMdbEnv* ev,            // context
      nsIMdbTableRowCursor** acqCursor) = 0;  // acquire clone with no dups
  // Note that MakeUniqueCursor() is never necessary for a cursor which was
  // created by table method nsIMdbTable::GetTableRowCursor(), because a table
  // never contains the same row as a member more than once.  However, a cursor
  // created by table method nsIMdbTable::FindRowMatches() might contain the
  // same row more than once, because the same row can generate a hit by more
  // than one column with a matching string prefix.  Note this method can
  // return the very same cursor instance with just an incremented refcount,
  // when the original cursor could not contain any duplicate rows (calling
  // CanHaveDupRowMembers() shows this case on a false return).  Otherwise
  // this method returns a different cursor instance.  Callers should not use
  // this MakeUniqueCursor() method lightly, because it tends to defeat the
  // purpose of lazy programming techniques, since it can force creation of
  // an explicit row collection in a new cursor's representation, in order to
  // inspect the row membership and remove any duplicates; this can have big
  // impact if a collection holds tens of thousands of rows or more, when
  // the original cursor with dups simply referenced rows indirectly by row
  // position ranges, without using an explicit row set representation.
  // Callers are encouraged to use nsIMdbCursor::GetCount() to determine
  // whether the row collection is very large (tens of thousands), and to
  // delay calling MakeUniqueCursor() when possible, until a user interface
  // element actually demands the creation of an explicit set representation.
  // } ----- end duplicate row removal methods -----

  // { ----- begin oid iteration methods -----
  NS_IMETHOD NextRowOid(        // get row id of next row in the table
      nsIMdbEnv* ev,            // context
      mdbOid* outOid,           // out row oid
      mdb_pos* outRowPos) = 0;  // zero-based position of the row in table
  // } ----- end oid iteration methods -----

  // { ----- begin row iteration methods -----
  NS_IMETHOD NextRow(      // get row cells from table for cells already in row
      nsIMdbEnv* ev,       // context
      nsIMdbRow** acqRow,  // acquire next row in table
      mdb_pos* outRowPos) = 0;  // zero-based position of the row in table

  NS_IMETHOD PrevRowOid(        // get row id of previous row in the table
      nsIMdbEnv* ev,            // context
      mdbOid* outOid,           // out row oid
      mdb_pos* outRowPos) = 0;  // zero-based position of the row in table
  // } ----- end oid iteration methods -----

  // { ----- begin row iteration methods -----
  NS_IMETHOD PrevRow(      // get row cells from table for cells already in row
      nsIMdbEnv* ev,       // context
      nsIMdbRow** acqRow,  // acquire previous row in table
      mdb_pos* outRowPos) = 0;  // zero-based position of the row in table

  // } ----- end row iteration methods -----

  // { ----- begin copy iteration methods -----
  // NS_IMETHOD NextRowCopy( // put row cells into sink only when already in
  // sink
  //   nsIMdbEnv* ev, // context
  //   nsIMdbRow* ioSinkRow, // sink for row cells read from next row
  //   mdbOid* outOid, // out row oid
  //   mdb_pos* outRowPos) = 0;    // zero-based position of the row in table
  //
  // NS_IMETHOD NextRowCopyAll( // put all row cells into sink, adding to sink
  //   nsIMdbEnv* ev, // context
  //   nsIMdbRow* ioSinkRow, // sink for row cells read from next row
  //   mdbOid* outOid, // out row oid
  //   mdb_pos* outRowPos) = 0;    // zero-based position of the row in table
  // } ----- end copy iteration methods -----

  // } ===== end nsIMdbTableRowCursor methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbTableRowCursor, NS_IMDBTABLEROWCURSOR_IID)

/*| nsIMdbRow: a collection of cells
**|
|*/

#define NS_IMDBROW_IID_STR "271e8d6e-183a-40e3-9f18-36913b4c7853"

#define NS_IMDBROW_IID                               \
  {                                                  \
    0x271e8d6e, 0x183a, 0x40e3, {                    \
      0x9f, 0x18, 0x36, 0x91, 0x3b, 0x4c, 0x78, 0x53 \
    }                                                \
  }

class nsIMdbRow : public nsIMdbCollection {  // cell tuple
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBROW_IID)
  // { ===== begin nsIMdbRow methods =====

  // { ----- begin cursor methods -----
  NS_IMETHOD GetRowCellCursor(  // make a cursor starting iteration at inCellPos
      nsIMdbEnv* ev,            // context
      mdb_pos inCellPos,        // zero-based ordinal position of cell in row
      nsIMdbRowCellCursor** acqCursor) = 0;  // acquire new cursor instance
  // } ----- end cursor methods -----

  // { ----- begin column methods -----
  NS_IMETHOD AddColumn(     // make sure a particular column is inside row
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // column to add
      const mdbYarn* inYarn) = 0;  // cell value to install

  NS_IMETHOD CutColumn(          // make sure a column is absent from the row
      nsIMdbEnv* ev,             // context
      mdb_column inColumn) = 0;  // column to ensure absent from row

  NS_IMETHOD CutAllColumns(  // remove all columns from the row
      nsIMdbEnv* ev) = 0;    // context
  // } ----- end column methods -----

  // { ----- begin cell methods -----
  NS_IMETHOD NewCell(       // get cell for specified column, or add new one
      nsIMdbEnv* ev,        // context
      mdb_column inColumn,  // column to add
      nsIMdbCell** acqCell) = 0;  // cell column and value

  NS_IMETHOD AddCell(  // copy a cell from another row to this row
      nsIMdbEnv* ev,   // context
      const nsIMdbCell* inCell) = 0;  // cell column and value

  NS_IMETHOD GetCell(             // find a cell in this row
      nsIMdbEnv* ev,              // context
      mdb_column inColumn,        // column to find
      nsIMdbCell** acqCell) = 0;  // cell for specified column, or null

  NS_IMETHOD EmptyAllCells(  // make all cells in row empty of content
      nsIMdbEnv* ev) = 0;    // context
  // } ----- end cell methods -----

  // { ----- begin row methods -----
  NS_IMETHOD AddRow(                // add all cells in another row to this one
      nsIMdbEnv* ev,                // context
      nsIMdbRow* ioSourceRow) = 0;  // row to union with

  NS_IMETHOD SetRow(                // make exact duplicate of another row
      nsIMdbEnv* ev,                // context
      nsIMdbRow* ioSourceRow) = 0;  // row to duplicate
  // } ----- end row methods -----

  // { ----- begin blob methods -----
  NS_IMETHOD SetCellYarn(nsIMdbEnv* ev,               // synonym for AddColumn()
                         mdb_column inColumn,         // column to write
                         const mdbYarn* inYarn) = 0;  // reads from yarn slots
  // make this text object contain content from the yarn's buffer

  NS_IMETHOD GetCellYarn(nsIMdbEnv* ev,
                         mdb_column inColumn,    // column to read
                         mdbYarn* outYarn) = 0;  // writes some yarn slots
  // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form

  NS_IMETHOD AliasCellYarn(nsIMdbEnv* ev,
                           mdb_column inColumn,    // column to alias
                           mdbYarn* outYarn) = 0;  // writes ALL yarn slots

  NS_IMETHOD NextCellYarn(nsIMdbEnv* ev,  // iterative version of GetCellYarn()
                          mdb_column* ioColumn,   // next column to read
                          mdbYarn* outYarn) = 0;  // writes some yarn slots
  // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
  //
  // The ioColumn argument is an inout parameter which initially contains the
  // last column accessed and returns the next column corresponding to the
  // content read into the yarn.  Callers should start with a zero column
  // value to say 'no previous column', which causes the first column to be
  // read.  Then the value returned in ioColumn is perfect for the next call
  // to NextCellYarn(), since it will then be the previous column accessed.
  // Callers need only examine the column token returned to see which cell
  // in the row is being read into the yarn.  When no more columns remain,
  // and the iteration has ended, ioColumn will return a zero token again.
  // So iterating over cells starts and ends with a zero column token.

  NS_IMETHOD SeekCellYarn(    // resembles nsIMdbRowCellCursor::SeekCell()
      nsIMdbEnv* ev,          // context
      mdb_pos inPos,          // position of cell in row sequence
      mdb_column* outColumn,  // column for this particular cell
      mdbYarn* outYarn) = 0;  // writes some yarn slots
  // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
  // Callers can pass nil for outYarn to indicate no interest in content, so
  // only the outColumn value is returned.  NOTE to subclasses: you must be
  // able to ignore outYarn when the pointer is nil; please do not crash.

  // } ----- end blob methods -----

  // } ===== end nsIMdbRow methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRow, NS_IMDBROW_IID)

/*| nsIMdbRowCellCursor: cursor class for iterating row cells
**|
**|| row: the cursor is associated with a specific row, which can be
**| set to a different row (which resets the position to -1 so the
**| next cell acquired is the first in the row.
**|
**|| NextCell: get the next cell in the row and return its position and
**| a new instance of a nsIMdbCell to represent this next cell.
|*/

#define NS_IMDBROWCELLCURSOR_IID_STR "b33371a7-5d63-4d10-85a8-e44dffe75c28"

#define NS_IMDBROWCELLCURSOR_IID                     \
  {                                                  \
    0x271e8d6e, 0x5d63, 0x4d10, {                    \
      0x85, 0xa8, 0xe4, 0x4d, 0xff, 0xe7, 0x5c, 0x28 \
    }                                                \
  }

class nsIMdbRowCellCursor : public nsISupports {  // cell collection iterator
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBROWCELLCURSOR_IID)
  // { ===== begin nsIMdbRowCellCursor methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD SetRow(nsIMdbEnv* ev, nsIMdbRow* ioRow) = 0;  // sets pos to -1
  NS_IMETHOD GetRow(nsIMdbEnv* ev, nsIMdbRow** acqRow) = 0;
  // } ----- end attribute methods -----

  // { ----- begin cell creation methods -----
  NS_IMETHOD MakeCell(            // get cell at current pos in the row
      nsIMdbEnv* ev,              // context
      mdb_column* outColumn,      // column for this particular cell
      mdb_pos* outPos,            // position of cell in row sequence
      nsIMdbCell** acqCell) = 0;  // the cell at inPos
  // } ----- end cell creation methods -----

  // { ----- begin cell seeking methods -----
  NS_IMETHOD SeekCell(            // same as SetRow() followed by MakeCell()
      nsIMdbEnv* ev,              // context
      mdb_pos inPos,              // position of cell in row sequence
      mdb_column* outColumn,      // column for this particular cell
      nsIMdbCell** acqCell) = 0;  // the cell at inPos
  // } ----- end cell seeking methods -----

  // { ----- begin cell iteration methods -----
  NS_IMETHOD NextCell(        // get next cell in the row
      nsIMdbEnv* ev,          // context
      nsIMdbCell** acqCell,   // changes to the next cell in the iteration
      mdb_column* outColumn,  // column for this particular cell
      mdb_pos* outPos) = 0;   // position of cell in row sequence

  NS_IMETHOD PickNextCell(  // get next cell in row within filter set
      nsIMdbEnv* ev,        // context
      nsIMdbCell* ioCell,   // changes to the next cell in the iteration
      const mdbColumnSet* inFilterSet,  // col set of actual caller interest
      mdb_column* outColumn,            // column for this particular cell
      mdb_pos* outPos) = 0;             // position of cell in row sequence

  // Note that inFilterSet should not have too many (many more than 10?)
  // cols, since this might imply a potential excessive consumption of time
  // over many cursor calls when looking for column and filter intersection.
  // } ----- end cell iteration methods -----

  // } ===== end nsIMdbRowCellCursor methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbRowCellCursor, NS_IMDBROWCELLCURSOR_IID)

/*| nsIMdbBlob: a base class for objects composed mainly of byte sequence state.
**| (This provides a base class for nsIMdbCell, so that cells themselves can
**| be used to set state in another cell, without extracting a buffer.)
|*/
class nsIMdbBlob : public nsISupports {  // a string with associated charset
 public:
  // { ===== begin nsIMdbBlob methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD SetBlob(nsIMdbEnv* ev,
                     nsIMdbBlob* ioBlob) = 0;  // reads inBlob slots
  // when inBlob is in the same suite, this might be fastest cell-to-cell

  NS_IMETHOD ClearBlob(  // make empty (so content has zero length)
      nsIMdbEnv* ev) = 0;
  // clearing a yarn is like SetYarn() with empty yarn instance content

  NS_IMETHOD GetBlobFill(nsIMdbEnv* ev,
                         mdb_fill* outFill) = 0;  // size of blob
  // Same value that would be put into mYarn_Fill, if one called GetYarn()
  // with a yarn instance that had mYarn_Buf==nil and mYarn_Size==0.

  NS_IMETHOD SetYarn(nsIMdbEnv* ev,
                     const mdbYarn* inYarn) = 0;  // reads from yarn slots
  // make this text object contain content from the yarn's buffer

  NS_IMETHOD GetYarn(nsIMdbEnv* ev,
                     mdbYarn* outYarn) = 0;  // writes some yarn slots
  // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form

  NS_IMETHOD AliasYarn(nsIMdbEnv* ev,
                       mdbYarn* outYarn) = 0;  // writes ALL yarn slots
  // AliasYarn() reveals sensitive internal text buffer state to the caller
  // by setting mYarn_Buf to point into the guts of this text implementation.
  //
  // The caller must take great care to avoid writing on this space, and to
  // avoid calling any method that would cause the state of this text object
  // to change (say by directly or indirectly setting the text to hold more
  // content that might grow the size of the buffer and free the old buffer).
  // In particular, callers should scrupulously avoid making calls into the
  // mdb interface to write any content while using the buffer pointer found
  // in the returned yarn instance.  Best safe usage involves copying content
  // into some other kind of external content representation beyond mdb.
  //
  // (The original design of this method a week earlier included the concept
  // of very fast and efficient cooperative locking via a pointer to some lock
  // member slot.  But let's ignore that complexity in the current design.)
  //
  // AliasYarn() is specifically intended as the first step in transferring
  // content from nsIMdbBlob to a nsString representation, without forcing extra
  // allocations and/or memory copies. (A standard nsIMdbBlob_AsString() utility
  // will use AliasYarn() as the first step in setting a nsString instance.)
  //
  // This is an alternative to the GetYarn() method, which has copy semantics
  // only; AliasYarn() relaxes a robust safety principle only for performance
  // reasons, to accommodate the need for callers to transform text content to
  // some other canonical representation that would necessitate an additional
  // copy and transformation when such is incompatible with the mdbYarn format.
  //
  // The implementation of AliasYarn() should have extremely little overhead
  // besides the virtual dispatch to the method implementation, and the code
  // necessary to populate all the mdbYarn member slots with internal buffer
  // address and metainformation that describes the buffer content.  Note that
  // mYarn_Grow must always be set to nil to indicate no resizing is allowed.

  // } ----- end attribute methods -----

  // } ===== end nsIMdbBlob methods =====
};

/*| nsIMdbCell: the text in a single column of a row.  The base nsIMdbBlob
**| class provides all the interface related to accessing cell text.
**|
**|| column: each cell in a row appears in a specific column, where this
**| column is identified by the an integer mdb_scope value (generated by
**| the StringToScopeToken() method in the containing nsIMdbPort instance).
**| Because a row cannot have more than one cell with the same column,
**| something must give if one calls SetColumn() with an existing column
**| in the same row. When this happens, the other cell is replaced with
**| this cell (and the old cell is closed if it has outstanding refs).
**|
**|| row: every cell instance is a part of some row, and every cell knows
**| which row is the parent row.  (Note this should be represented by a
**| weak backpointer, so that outstanding cell references cannot keep a
**| row open that should be closed. Otherwise we'd have ref graph cycles.)
**|
**|| text: a cell can either be text, or it can have a child row or table,
**| but not both at once.  If text is read from a cell with a child, the text
**| content should be empty (for AliasYarn()) or a description of the type
**| of child (perhaps "mdb:cell:child:row" or "mdb:cell:child:table").
**|
**|| child: a cell might reference another row or a table, rather than text.
**| The interface for putting and getting children rows and tables was first
**| defined in the nsIMdbTable interface, but then this was moved to this cell
**| interface as more natural.
|*/

#define NS_IMDBCELL_IID                              \
  {                                                  \
    0xa3b62f71, 0xa181, 0x4a91, {                    \
      0xb6, 0x6b, 0x27, 0x10, 0x9b, 0x88, 0x98, 0x35 \
    }                                                \
  }

#define NS_IMDBCELL_IID_STR = "a3b62f71-a181-4a91-b66b-27109b889835"

class nsIMdbCell
    : public nsIMdbBlob {  // text attribute in row with column scope
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBTABLEROWCURSOR_IID)
  // { ===== begin nsIMdbCell methods =====

  // { ----- begin attribute methods -----
  NS_IMETHOD SetColumn(nsIMdbEnv* ev, mdb_column inColumn) = 0;
  NS_IMETHOD GetColumn(nsIMdbEnv* ev, mdb_column* outColumn) = 0;

  NS_IMETHOD GetCellInfo(  // all cell metainfo except actual content
      nsIMdbEnv* ev,
      mdb_column* outColumn,         // the column in the containing row
      mdb_fill* outBlobFill,         // the size of text content in bytes
      mdbOid* outChildOid,           // oid of possible row or table child
      mdb_bool* outIsRowChild) = 0;  // nonzero if child, and a row child

  // Checking all cell metainfo is a good way to avoid forcing a large cell
  // in to memory when you don't actually want to use the content.

  NS_IMETHOD GetRow(nsIMdbEnv* ev,  // parent row for this cell
                    nsIMdbRow** acqRow) = 0;
  NS_IMETHOD GetPort(nsIMdbEnv* ev,  // port containing cell
                     nsIMdbPort** acqPort) = 0;
  // } ----- end attribute methods -----

  // { ----- begin children methods -----
  NS_IMETHOD HasAnyChild(  // does cell have a child instead of text?
      nsIMdbEnv* ev,
      mdbOid* outOid,  // out id of row or table (or unbound if no child)
      mdb_bool* outIsRow) =
      0;  // nonzero if child is a row (rather than a table)

  NS_IMETHOD GetAnyChild(           // access table of specific attribute
      nsIMdbEnv* ev,                // context
      nsIMdbRow** acqRow,           // child row (or null)
      nsIMdbTable** acqTable) = 0;  // child table (or null)

  NS_IMETHOD SetChildRow(     // access table of specific attribute
      nsIMdbEnv* ev,          // context
      nsIMdbRow* ioRow) = 0;  // inRow must be bound inside this same db port

  NS_IMETHOD GetChildRow(       // access row of specific attribute
      nsIMdbEnv* ev,            // context
      nsIMdbRow** acqRow) = 0;  // acquire child row (or nil if no child)

  NS_IMETHOD SetChildTable(  // access table of specific attribute
      nsIMdbEnv* ev,         // context
      nsIMdbTable* inTable) =
      0;  // table must be bound inside this same db port

  NS_IMETHOD GetChildTable(         // access table of specific attribute
      nsIMdbEnv* ev,                // context
      nsIMdbTable** acqTable) = 0;  // acquire child table (or nil if no child)
  // } ----- end children methods -----

  // } ===== end nsIMdbCell methods =====
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbCell, NS_IMDBTABLEROWCURSOR_IID)

// } %%%%% end C++ abstract class interfaces %%%%%

// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

#endif /* _MDB_ */