Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge latest trunk into this branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | wal-read-change |
Files: | files | file ages | folders |
SHA1: |
ab93024da7bd577d8850b417aff8597a |
User & Date: | dan 2015-08-28 15:50:24.380 |
Context
2015-08-28
| ||
16:18 | When searching the wal file for a frame, do not search that part that was already checkpointed when the transaction was opened. (check-in: a84cf4f5d3 user: dan tags: trunk) | |
15:50 | Merge latest trunk into this branch. (Closed-Leaf check-in: ab93024da7 user: dan tags: wal-read-change) | |
03:48 | Add the json_check() function, which returns its argument if the argument is well-formed JSON or which throws an error otherwise. (check-in: 64abb65d4d user: drh tags: trunk) | |
2015-08-13
| ||
20:23 | When searching the wal file for a frame, do not search that part that was already checkpointed when the snapshot being read was at the head of the wal file. (check-in: 90760e7232 user: dan tags: wal-read-change) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c # Source code to the library files needed by the test fixture # TESTSRC2 = \ | > > | 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/json1.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c # Source code to the library files needed by the test fixture # TESTSRC2 = \ |
︙ | ︙ |
Changes to Makefile.msc.
︙ | ︙ | |||
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 | $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ fts5.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\wholenumber.c # Source code to the library files needed by the test fixture # | > > | 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 | $(TOP)\ext\misc\eval.c \ $(TOP)\ext\misc\fileio.c \ $(TOP)\ext\misc\fuzzer.c \ fts5.c \ $(TOP)\ext\fts5\fts5_tcl.c \ $(TOP)\ext\fts5\fts5_test_mi.c \ $(TOP)\ext\misc\ieee754.c \ $(TOP)\ext\misc\json1.c \ $(TOP)\ext\misc\nextchar.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\wholenumber.c # Source code to the library files needed by the test fixture # |
︙ | ︙ |
Changes to ext/fts5/fts5_expr.c.
︙ | ︙ | |||
1862 1863 1864 1865 1866 1867 1868 | const char **azConfig; /* Array of arguments for Fts5Config */ const char *zNearsetCmd = "nearset"; int nConfig; /* Size of azConfig[] */ Fts5Config *pConfig = 0; int iArg = 1; if( nArg<1 ){ | | | 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 | const char **azConfig; /* Array of arguments for Fts5Config */ const char *zNearsetCmd = "nearset"; int nConfig; /* Size of azConfig[] */ Fts5Config *pConfig = 0; int iArg = 1; if( nArg<1 ){ zErr = sqlite3_mprintf("wrong number of arguments to function %s", bTcl ? "fts5_expr_tcl" : "fts5_expr" ); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); return; } |
︙ | ︙ |
Added ext/misc/json1.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** 2015-08-12 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ****************************************************************************** ** ** This SQLite extension implements JSON functions. The interface is ** modeled after MySQL JSON functions: ** ** https://dev.mysql.com/doc/refman/5.7/en/json.html ** ** For the time being, all JSON is stored as pure text. (We might add ** a JSONB type in the future which stores a binary encoding of JSON in ** a BLOB, but there is no support for JSONB in the current implementation. ** This implementation parses JSON text at 250 MB/s, so it is hard to see ** how JSONB might improve on that.) */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <stdarg.h> #define UNUSED_PARAM(X) (void)(X) /* Unsigned integer types */ typedef sqlite3_uint64 u64; typedef unsigned int u32; typedef unsigned char u8; /* Objects */ typedef struct JsonString JsonString; typedef struct JsonNode JsonNode; typedef struct JsonParse JsonParse; /* An instance of this object represents a JSON string ** under construction. Really, this is a generic string accumulator ** that can be and is used to create strings other than JSON. */ struct JsonString { sqlite3_context *pCtx; /* Function context - put error messages here */ char *zBuf; /* Append JSON content here */ u64 nAlloc; /* Bytes of storage available in zBuf[] */ u64 nUsed; /* Bytes of zBuf[] currently used */ u8 bStatic; /* True if zBuf is static space */ u8 bErr; /* True if an error has been encountered */ char zSpace[100]; /* Initial static space */ }; /* JSON type values */ #define JSON_NULL 0 #define JSON_TRUE 1 #define JSON_FALSE 2 #define JSON_INT 3 #define JSON_REAL 4 #define JSON_STRING 5 #define JSON_ARRAY 6 #define JSON_OBJECT 7 /* ** Names of the various JSON types: */ static const char * const jsonType[] = { "null", "true", "false", "integer", "real", "text", "array", "object" }; /* Bit values for the JsonNode.jnFlag field */ #define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */ #define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */ #define JNODE_REMOVE 0x04 /* Do not output */ #define JNODE_REPLACE 0x08 /* Replace with JsonNode.iVal */ #define JNODE_APPEND 0x10 /* More ARRAY/OBJECT entries at u.iAppend */ #define JNODE_JSON 0x20 /* Treat REPLACE as JSON text */ /* A single node of parsed JSON */ struct JsonNode { u8 eType; /* One of the JSON_ type values */ u8 jnFlags; /* JNODE flags */ u8 iVal; /* Replacement value when JNODE_REPLACE */ u32 n; /* Bytes of content, or number of sub-nodes */ union { const char *zJContent; /* Content for INT, REAL, and STRING */ u32 iAppend; /* More terms for ARRAY and OBJECT */ u32 iKey; /* Key for ARRAY objects in json_tree() */ } u; }; /* A completely parsed JSON string */ struct JsonParse { u32 nNode; /* Number of slots of aNode[] used */ u32 nAlloc; /* Number of slots of aNode[] allocated */ JsonNode *aNode; /* Array of nodes containing the parse */ const char *zJson; /* Original JSON string */ u32 *aUp; /* Index of parent of each node */ u8 oom; /* Set to true if out of memory */ }; /************************************************************************** ** Utility routines for dealing with JsonString objects **************************************************************************/ /* Set the JsonString object to an empty string */ static void jsonZero(JsonString *p){ p->zBuf = p->zSpace; p->nAlloc = sizeof(p->zSpace); p->nUsed = 0; p->bStatic = 1; } /* Initialize the JsonString object */ static void jsonInit(JsonString *p, sqlite3_context *pCtx){ p->pCtx = pCtx; p->bErr = 0; jsonZero(p); } /* Free all allocated memory and reset the JsonString object back to its ** initial state. */ static void jsonReset(JsonString *p){ if( !p->bStatic ) sqlite3_free(p->zBuf); jsonZero(p); } /* Report an out-of-memory (OOM) condition */ static void jsonOom(JsonString *p){ if( !p->bErr ){ p->bErr = 1; sqlite3_result_error_nomem(p->pCtx); jsonReset(p); } } /* Enlarge pJson->zBuf so that it can hold at least N more bytes. ** Return zero on success. Return non-zero on an OOM error */ static int jsonGrow(JsonString *p, u32 N){ u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10; char *zNew; if( p->bStatic ){ if( p->bErr ) return 1; zNew = sqlite3_malloc64(nTotal); if( zNew==0 ){ jsonOom(p); return SQLITE_NOMEM; } memcpy(zNew, p->zBuf, (size_t)p->nUsed); p->zBuf = zNew; p->bStatic = 0; }else{ zNew = sqlite3_realloc64(p->zBuf, nTotal); if( zNew==0 ){ jsonOom(p); return SQLITE_NOMEM; } p->zBuf = zNew; } p->nAlloc = nTotal; return SQLITE_OK; } /* Append N bytes from zIn onto the end of the JsonString string. */ static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){ if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return; memcpy(p->zBuf+p->nUsed, zIn, N); p->nUsed += N; } /* Append formatted text (not to exceed N bytes) to the JsonString. */ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){ va_list ap; if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return; va_start(ap, zFormat); sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap); va_end(ap); p->nUsed += (int)strlen(p->zBuf+p->nUsed); } /* Append a single character */ static void jsonAppendChar(JsonString *p, char c){ if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return; p->zBuf[p->nUsed++] = c; } /* Append a comma separator to the output buffer, if the previous ** character is not '[' or '{'. */ static void jsonAppendSeparator(JsonString *p){ char c; if( p->nUsed==0 ) return; c = p->zBuf[p->nUsed-1]; if( c!='[' && c!='{' ) jsonAppendChar(p, ','); } /* Append the N-byte string in zIn to the end of the JsonString string ** under construction. Enclose the string in "..." and escape ** any double-quotes or backslash characters contained within the ** string. */ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){ u32 i; if( (N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0 ) return; p->zBuf[p->nUsed++] = '"'; for(i=0; i<N; i++){ char c = zIn[i]; if( c=='"' || c=='\\' ){ if( (p->nUsed+N+1-i > p->nAlloc) && jsonGrow(p,N+1-i)!=0 ) return; p->zBuf[p->nUsed++] = '\\'; } p->zBuf[p->nUsed++] = c; } p->zBuf[p->nUsed++] = '"'; } /* ** Append a function parameter value to the JSON string under ** construction. */ static void jsonAppendValue( JsonString *p, /* Append to this JSON string */ sqlite3_value *pValue, /* Value to append */ u8 textIsJson /* Try to treat text values as JSON */ ){ switch( sqlite3_value_type(pValue) ){ case SQLITE_NULL: { jsonAppendRaw(p, "null", 4); break; } case SQLITE_INTEGER: case SQLITE_FLOAT: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); jsonAppendRaw(p, z, n); break; } case SQLITE_TEXT: { const char *z = (const char*)sqlite3_value_text(pValue); u32 n = (u32)sqlite3_value_bytes(pValue); if( textIsJson ){ jsonAppendRaw(p, z, n); }else{ jsonAppendString(p, z, n); } break; } default: { if( p->bErr==0 ){ sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1); p->bErr = 1; jsonReset(p); } break; } } } /* Make the JSON in p the result of the SQL function. */ static void jsonResult(JsonString *p){ if( p->bErr==0 ){ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, SQLITE_UTF8); jsonZero(p); } assert( p->bStatic ); } /************************************************************************** ** Utility routines for dealing with JsonNode and JsonParse objects **************************************************************************/ /* ** Return the number of consecutive JsonNode slots need to represent ** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and ** OBJECT types, the number might be larger. ** ** Appended elements are not counted. The value returned is the number ** by which the JsonNode counter should increment in order to go to the ** next peer value. */ static u32 jsonNodeSize(JsonNode *pNode){ return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1; } /* ** Reclaim all memory allocated by a JsonParse object. But do not ** delete the JsonParse object itself. */ static void jsonParseReset(JsonParse *pParse){ sqlite3_free(pParse->aNode); pParse->aNode = 0; pParse->nNode = 0; pParse->nAlloc = 0; sqlite3_free(pParse->aUp); pParse->aUp = 0; } /* ** Convert the JsonNode pNode into a pure JSON string and ** append to pOut. Subsubstructure is also included. Return ** the number of JsonNode objects that are encoded. */ static void jsonRenderNode( JsonNode *pNode, /* The node to render */ JsonString *pOut, /* Write JSON here */ sqlite3_value **aReplace /* Replacement values */ ){ switch( pNode->eType ){ case JSON_NULL: { jsonAppendRaw(pOut, "null", 4); break; } case JSON_TRUE: { jsonAppendRaw(pOut, "true", 4); break; } case JSON_FALSE: { jsonAppendRaw(pOut, "false", 5); break; } case JSON_STRING: { if( pNode->jnFlags & JNODE_RAW ){ jsonAppendString(pOut, pNode->u.zJContent, pNode->n); break; } /* Fall through into the next case */ } case JSON_REAL: case JSON_INT: { jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n); break; } case JSON_ARRAY: { u32 j = 1; jsonAppendChar(pOut, '['); for(;;){ while( j<=pNode->n ){ if( pNode[j].jnFlags & (JNODE_REMOVE|JNODE_REPLACE) ){ if( pNode[j].jnFlags & JNODE_REPLACE ){ jsonAppendSeparator(pOut); jsonAppendValue(pOut, aReplace[pNode[j].iVal], (pNode[j].jnFlags & JNODE_JSON)!=0); } }else{ jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); } j += jsonNodeSize(&pNode[j]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; pNode = &pNode[pNode->u.iAppend]; j = 1; } jsonAppendChar(pOut, ']'); break; } case JSON_OBJECT: { u32 j = 1; jsonAppendChar(pOut, '{'); for(;;){ while( j<=pNode->n ){ if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){ jsonAppendSeparator(pOut); jsonRenderNode(&pNode[j], pOut, aReplace); jsonAppendChar(pOut, ':'); if( pNode[j+1].jnFlags & JNODE_REPLACE ){ jsonAppendValue(pOut, aReplace[pNode[j+1].iVal], (pNode[j+1].jnFlags & JNODE_JSON)!=0); }else{ jsonRenderNode(&pNode[j+1], pOut, aReplace); } } j += 1 + jsonNodeSize(&pNode[j+1]); } if( (pNode->jnFlags & JNODE_APPEND)==0 ) break; pNode = &pNode[pNode->u.iAppend]; j = 1; } jsonAppendChar(pOut, '}'); break; } } } /* ** Make the JsonNode the return value of the function. */ static void jsonReturn( JsonNode *pNode, /* Node to return */ sqlite3_context *pCtx, /* Return value for this function */ sqlite3_value **aReplace /* Array of replacement values */ ){ switch( pNode->eType ){ case JSON_NULL: { sqlite3_result_null(pCtx); break; } case JSON_TRUE: { sqlite3_result_int(pCtx, 1); break; } case JSON_FALSE: { sqlite3_result_int(pCtx, 0); break; } case JSON_REAL: { double r = strtod(pNode->u.zJContent, 0); sqlite3_result_double(pCtx, r); break; } case JSON_INT: { sqlite3_int64 i = 0; const char *z = pNode->u.zJContent; if( z[0]=='-' ){ z++; } while( z[0]>='0' && z[0]<='9' ){ i = i*10 + *(z++) - '0'; } if( pNode->u.zJContent[0]=='-' ){ i = -i; } sqlite3_result_int64(pCtx, i); break; } case JSON_STRING: { if( pNode->jnFlags & JNODE_RAW ){ sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n, SQLITE_TRANSIENT); }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){ /* JSON formatted without any backslash-escapes */ sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2, SQLITE_TRANSIENT); }else{ /* Translate JSON formatted string into raw text */ u32 i; u32 n = pNode->n; const char *z = pNode->u.zJContent; char *zOut; u32 j; zOut = sqlite3_malloc( n+1 ); if( zOut==0 ){ sqlite3_result_error_nomem(pCtx); break; } for(i=1, j=0; i<n-1; i++){ char c = z[i]; if( c!='\\' ){ zOut[j++] = c; }else{ c = z[++i]; if( c=='u' ){ u32 v = 0, k; for(k=0; k<4 && i<n-2; i++, k++){ c = z[i+1]; if( c>='0' && c<='9' ) v = v*16 + c - '0'; else if( c>='A' && c<='F' ) v = v*16 + c - 'A' + 10; else if( c>='a' && c<='f' ) v = v*16 + c - 'a' + 10; else break; } if( v==0 ) break; if( v<=0x7f ){ zOut[j++] = v; }else if( v<=0x7ff ){ zOut[j++] = 0xc0 | (v>>6); zOut[j++] = 0x80 | (v&0x3f); }else{ zOut[j++] = 0xe0 | (v>>12); zOut[j++] = 0x80 | ((v>>6)&0x3f); zOut[j++] = 0x80 | (v&0x3f); } }else{ if( c=='b' ){ c = '\b'; }else if( c=='f' ){ c = '\f'; }else if( c=='n' ){ c = '\n'; }else if( c=='r' ){ c = '\r'; }else if( c=='t' ){ c = '\t'; } zOut[j++] = c; } } } zOut[j] = 0; sqlite3_result_text(pCtx, zOut, j, sqlite3_free); } break; } case JSON_ARRAY: case JSON_OBJECT: { JsonString s; jsonInit(&s, pCtx); jsonRenderNode(pNode, &s, aReplace); jsonResult(&s); break; } } } /* ** Create a new JsonNode instance based on the arguments and append that ** instance to the JsonParse. Return the index in pParse->aNode[] of the ** new node, or -1 if a memory allocation fails. */ static int jsonParseAddNode( JsonParse *pParse, /* Append the node to this object */ u32 eType, /* Node type */ u32 n, /* Content size or sub-node count */ const char *zContent /* Content */ ){ JsonNode *p; if( pParse->nNode>=pParse->nAlloc ){ u32 nNew; JsonNode *pNew; if( pParse->oom ) return -1; nNew = pParse->nAlloc*2 + 10; if( nNew<=pParse->nNode ){ pParse->oom = 1; return -1; } pNew = sqlite3_realloc(pParse->aNode, sizeof(JsonNode)*nNew); if( pNew==0 ){ pParse->oom = 1; return -1; } pParse->nAlloc = nNew; pParse->aNode = pNew; } p = &pParse->aNode[pParse->nNode]; p->eType = (u8)eType; p->jnFlags = 0; p->iVal = 0; p->n = n; p->u.zJContent = zContent; return pParse->nNode++; } /* ** Parse a single JSON value which begins at pParse->zJson[i]. Return the ** index of the first character past the end of the value parsed. ** ** Return negative for a syntax error. Special cases: return -2 if the ** first non-whitespace character is '}' and return -3 if the first ** non-whitespace character is ']'. */ static int jsonParseValue(JsonParse *pParse, u32 i){ char c; u32 j; int iThis; int x; while( isspace(pParse->zJson[i]) ){ i++; } if( (c = pParse->zJson[i])==0 ) return 0; if( c=='{' ){ /* Parse object */ iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ while( isspace(pParse->zJson[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } if( pParse->oom ) return -1; if( pParse->aNode[pParse->nNode-1].eType!=JSON_STRING ) return -1; j = x; while( isspace(pParse->zJson[j]) ){ j++; } if( pParse->zJson[j]!=':' ) return -1; j++; x = jsonParseValue(pParse, j); if( x<0 ) return -1; j = x; while( isspace(pParse->zJson[j]) ){ j++; } c = pParse->zJson[j]; if( c==',' ) continue; if( c!='}' ) return -1; break; } pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; }else if( c=='[' ){ /* Parse array */ iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); if( iThis<0 ) return -1; for(j=i+1;;j++){ while( isspace(pParse->zJson[j]) ){ j++; } x = jsonParseValue(pParse, j); if( x<0 ){ if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1; return -1; } j = x; while( isspace(pParse->zJson[j]) ){ j++; } c = pParse->zJson[j]; if( c==',' ) continue; if( c!=']' ) return -1; break; } pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1; return j+1; }else if( c=='"' ){ /* Parse string */ u8 jnFlags = 0; j = i+1; for(;;){ c = pParse->zJson[j]; if( c==0 ) return -1; if( c=='\\' ){ c = pParse->zJson[++j]; if( c==0 ) return -1; jnFlags = JNODE_ESCAPE; }else if( c=='"' ){ break; } j++; } jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]); if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags; return j+1; }else if( c=='n' && strncmp(pParse->zJson+i,"null",4)==0 && !isalnum(pParse->zJson[i+4]) ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return i+4; }else if( c=='t' && strncmp(pParse->zJson+i,"true",4)==0 && !isalnum(pParse->zJson[i+4]) ){ jsonParseAddNode(pParse, JSON_TRUE, 0, 0); return i+4; }else if( c=='f' && strncmp(pParse->zJson+i,"false",5)==0 && !isalnum(pParse->zJson[i+5]) ){ jsonParseAddNode(pParse, JSON_FALSE, 0, 0); return i+5; }else if( c=='-' || (c>='0' && c<='9') ){ /* Parse number */ u8 seenDP = 0; u8 seenE = 0; j = i+1; for(;; j++){ c = pParse->zJson[j]; if( c>='0' && c<='9' ) continue; if( c=='.' ){ if( pParse->zJson[j-1]=='-' ) return -1; if( seenDP ) return -1; seenDP = 1; continue; } if( c=='e' || c=='E' ){ if( pParse->zJson[j-1]<'0' ) return -1; if( seenE ) return -1; seenDP = seenE = 1; c = pParse->zJson[j+1]; if( c=='+' || c=='-' ){ j++; c = pParse->zJson[j+1]; } if( c<'0' || c>'0' ) return -1; continue; } break; } if( pParse->zJson[j-1]<'0' ) return -1; jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT, j - i, &pParse->zJson[i]); return j; }else if( c=='}' ){ return -2; /* End of {...} */ }else if( c==']' ){ return -3; /* End of [...] */ }else{ return -1; /* Syntax error */ } } /* ** Parse a complete JSON string. Return 0 on success or non-zero if there ** are any errors. If an error occurs, free all memory associated with ** pParse. ** ** pParse is uninitialized when this routine is called. */ static int jsonParse( JsonParse *pParse, /* Initialize and fill this JsonParse object */ sqlite3_context *pCtx, /* Report errors here */ const char *zJson /* Input JSON text to be parsed */ ){ int i; memset(pParse, 0, sizeof(*pParse)); if( zJson==0 ) return 1; pParse->zJson = zJson; i = jsonParseValue(pParse, 0); if( pParse->oom ) i = -1; if( i>0 ){ while( isspace(zJson[i]) ) i++; if( zJson[i] ) i = -1; } if( i<0 ){ if( pParse->oom && pCtx!=0 ) sqlite3_result_error_nomem(pCtx); jsonParseReset(pParse); return 1; } return 0; } /* Mark node i of pParse as being a child of iParent. Call recursively ** to fill in all the descendants of node i. */ static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){ JsonNode *pNode = &pParse->aNode[i]; u32 j; pParse->aUp[i] = iParent; switch( pNode->eType ){ case JSON_ARRAY: { for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){ jsonParseFillInParentage(pParse, i+j, i); } break; } case JSON_OBJECT: { for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){ pParse->aUp[i+j] = i; jsonParseFillInParentage(pParse, i+j+1, i); } break; } default: { break; } } } /* ** Compute the parentage of all nodes in a completed parse. */ static int jsonParseFindParents(JsonParse *pParse){ u32 *aUp; assert( pParse->aUp==0 ); aUp = pParse->aUp = sqlite3_malloc( sizeof(u32)*pParse->nNode ); if( aUp==0 ){ pParse->oom = 1; return SQLITE_NOMEM; } jsonParseFillInParentage(pParse, 0, 0); return SQLITE_OK; } /* forward declaration */ static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*); /* ** Search along zPath to find the node specified. Return a pointer ** to that node, or NULL if zPath is malformed or if there is no such ** node. ** ** If pApnd!=0, then try to append new nodes to complete zPath if it is ** possible to do so and if no existing node corresponds to zPath. If ** new nodes are appended *pApnd is set to 1. */ static JsonNode *jsonLookup( JsonParse *pParse, /* The JSON to search */ u32 iRoot, /* Begin the search at this node */ const char *zPath, /* The path to search */ int *pApnd /* Append nodes to complete path if not NULL */ ){ u32 i, j, nKey; const char *zKey; JsonNode *pRoot = &pParse->aNode[iRoot]; if( zPath[0]==0 ) return pRoot; if( zPath[0]=='.' ){ if( pRoot->eType!=JSON_OBJECT ) return 0; zPath++; if( zPath[0]=='"' ){ zKey = zPath + 1; for(i=1; zPath[i] && zPath[i]!='"'; i++){} nKey = i-1; if( zPath[i] ) i++; }else{ zKey = zPath; for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){} nKey = i; } if( nKey==0 ) return 0; j = 1; for(;;){ while( j<=pRoot->n ){ if( pRoot[j].n==nKey+2 && strncmp(&pRoot[j].u.zJContent[1],zKey,nKey)==0 ){ return jsonLookup(pParse, iRoot+j+1, &zPath[i], pApnd); } j++; j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; } if( pApnd ){ u32 iStart, iLabel; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0); iLabel = jsonParseAddNode(pParse, JSON_STRING, i, zPath); zPath += i; pNode = jsonLookupAppend(pParse, zPath, pApnd); if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; pParse->aNode[iLabel].jnFlags |= JNODE_RAW; } return pNode; } }else if( zPath[0]=='[' && isdigit(zPath[1]) ){ if( pRoot->eType!=JSON_ARRAY ) return 0; i = 0; zPath++; while( isdigit(zPath[0]) ){ i = i*10 + zPath[0] - '0'; zPath++; } if( zPath[0]!=']' ) return 0; zPath++; j = 1; for(;;){ while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){ if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--; j += jsonNodeSize(&pRoot[j]); } if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break; iRoot += pRoot->u.iAppend; pRoot = &pParse->aNode[iRoot]; j = 1; } if( j<=pRoot->n ){ return jsonLookup(pParse, iRoot+j, zPath, pApnd); } if( i==0 && pApnd ){ u32 iStart; JsonNode *pNode; iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0); pNode = jsonLookupAppend(pParse, zPath, pApnd); if( pParse->oom ) return 0; if( pNode ){ pRoot = &pParse->aNode[iRoot]; pRoot->u.iAppend = iStart - iRoot; pRoot->jnFlags |= JNODE_APPEND; } return pNode; } } return 0; } /* ** Append content to pParse that will complete zPath. Return a pointer ** to the inserted node, or return NULL if the append fails. */ static JsonNode *jsonLookupAppend( JsonParse *pParse, /* Append content to the JSON parse */ const char *zPath, /* Description of content to append */ int *pApnd /* Set this flag to 1 */ ){ *pApnd = 1; if( zPath[0]==0 ){ jsonParseAddNode(pParse, JSON_NULL, 0, 0); return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1]; } if( zPath[0]=='.' ){ jsonParseAddNode(pParse, JSON_OBJECT, 0, 0); }else if( strncmp(zPath,"[0]",3)==0 ){ jsonParseAddNode(pParse, JSON_ARRAY, 0, 0); }else{ return 0; } if( pParse->oom ) return 0; return jsonLookup(pParse, pParse->nNode-1, zPath, pApnd); } /* ** Report the wrong number of arguments for json_insert(), json_replace() ** or json_set(). */ static void jsonWrongNumArgs( sqlite3_context *pCtx, const char *zFuncName ){ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments", zFuncName); sqlite3_result_error(pCtx, zMsg, -1); sqlite3_free(zMsg); } /**************************************************************************** ** SQL functions used for testing and debugging ****************************************************************************/ #ifdef SQLITE_DEBUG /* ** The json_parse(JSON) function returns a string which describes ** a parse of the JSON provided. Or it returns NULL if JSON is not ** well-formed. */ static void jsonParseFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonString s; /* Output string - not real JSON */ JsonParse x; /* The parse */ u32 i; assert( argc==1 ); if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; jsonParseFindParents(&x); jsonInit(&s, ctx); for(i=0; i<x.nNode; i++){ jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%d\n", i, jsonType[x.aNode[i].eType], x.aNode[i].n, x.aUp[i]); if( x.aNode[i].u.zJContent!=0 ){ jsonAppendRaw(&s, " text: ", 10); jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n); jsonAppendRaw(&s, "\n", 1); } } jsonParseReset(&x); jsonResult(&s); } /* ** The json_test1(JSON) function parses and rebuilds the JSON string. */ static void jsonTest1Func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; jsonReturn(x.aNode, ctx, 0); jsonParseReset(&x); } /* ** The json_nodecount(JSON) function returns the number of nodes in the ** input JSON string. */ static void jsonNodeCountFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; sqlite3_result_int64(ctx, (sqlite3_int64)x.nNode); jsonParseReset(&x); } #endif /* SQLITE_DEBUG */ /**************************************************************************** ** SQL function implementations ****************************************************************************/ /* ** Implementation of the json_array(VALUE,...) function. Return a JSON ** array that contains all values given in arguments. Or if any argument ** is a BLOB, throw an error. */ static void jsonArrayFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; JsonString jx; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); for(i=0; i<argc; i++){ jsonAppendSeparator(&jx); jsonAppendValue(&jx, argv[i], 0); } jsonAppendChar(&jx, ']'); jsonResult(&jx); } /* ** json_array_length(JSON) ** json_array_length(JSON, PATH) ** ** Return the number of elements in the top-level JSON array. ** Return 0 if the input is not a well-formed JSON array. */ static void jsonArrayLengthFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ sqlite3_int64 n = 0; u32 i; const char *zPath; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 ) return; if( zPath[0]!='$' ) return; zPath++; }else{ zPath = 0; } if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0]))==0 ){ if( x.nNode ){ JsonNode *pNode = x.aNode; if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0); if( pNode->eType==JSON_ARRAY ){ assert( (pNode->jnFlags & JNODE_APPEND)==0 ); for(i=1; i<=pNode->n; n++){ i += jsonNodeSize(&pNode[i]); } } } jsonParseReset(&x); } if( !x.oom ) sqlite3_result_int64(ctx, n); } /* ** json_check(JSON) ** ** Check the JSON argument to verify that it is well-formed. Return a ** compacted version of the argument (with white-space removed) if the ** argument is well-formed. Through an error if the argument is not ** correctly formatted JSON. */ static void jsonCheckFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ){ sqlite3_result_error(ctx, "malformed JSON", -1); return; } jsonReturn(x.aNode, ctx, argv); jsonParseReset(&x); } /* ** json_extract(JSON, PATH) ** ** Return the element described by PATH. Return NULL if JSON is not ** valid JSON or if there is no PATH element or if PATH is malformed. */ static void jsonExtractFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; assert( argc==2 ); zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 ) return; if( zPath[0]!='$' ) return; zPath++; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; pNode = jsonLookup(&x, 0, zPath, 0); if( pNode ){ jsonReturn(pNode, ctx, 0); } jsonParseReset(&x); } /* ** Implementation of the json_object(NAME,VALUE,...) function. Return a JSON ** object that contains all name/value given in arguments. Or if any name ** is not a string or if any value is a BLOB, throw an error. */ static void jsonObjectFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ int i; JsonString jx; const char *z; u32 n; if( argc&1 ){ sqlite3_result_error(ctx, "json_object() requires an even number " "of arguments", -1); return; } jsonInit(&jx, ctx); jsonAppendChar(&jx, '{'); for(i=0; i<argc; i+=2){ if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){ sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1); jsonZero(&jx); return; } jsonAppendSeparator(&jx); z = (const char*)sqlite3_value_text(argv[i]); n = (u32)sqlite3_value_bytes(argv[i]); jsonAppendString(&jx, z, n); jsonAppendChar(&jx, ':'); jsonAppendValue(&jx, argv[i+1], 0); } jsonAppendChar(&jx, '}'); jsonResult(&jx); } /* ** json_remove(JSON, PATH, ...) ** ** Remove the named elements from JSON and return the result. Ill-formed ** PATH arguments are silently ignored. If JSON is ill-formed, then NULL ** is returned. */ static void jsonRemoveFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; u32 i; if( argc<1 ) return; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( x.nNode ){ for(i=1; i<(u32)argc; i++){ zPath = (const char*)sqlite3_value_text(argv[i]); if( zPath==0 ) continue; if( zPath[0]!='$' ) continue; pNode = jsonLookup(&x, 0, &zPath[1], 0); if( pNode ) pNode->jnFlags |= JNODE_REMOVE; } if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){ jsonReturn(x.aNode, ctx, 0); } } jsonParseReset(&x); } /* ** json_replace(JSON, PATH, VALUE, ...) ** ** Replace the value at PATH with VALUE. If PATH does not already exist, ** this routine is a no-op. If JSON is ill-formed, return NULL. */ static void jsonReplaceFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; u32 i; if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, "replace"); return; } if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( x.nNode ){ for(i=1; i<(u32)argc; i+=2){ u8 jnFlags = JNODE_REPLACE; zPath = (const char*)sqlite3_value_text(argv[i]); if( zPath==0 ) continue; if( zPath[0]!='$' ) continue; if( zPath[1]=='$' ){ zPath++; jnFlags = JNODE_REPLACE|JNODE_JSON; } pNode = jsonLookup(&x, 0, &zPath[1], 0); if( pNode ){ pNode->jnFlags &= ~JNODE_JSON; pNode->jnFlags |= jnFlags; pNode->iVal = i+1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); }else{ jsonReturn(x.aNode, ctx, argv); } } jsonParseReset(&x); } /* ** json_set(JSON, PATH, VALUE, ...) ** ** Set the value at PATH to VALUE. Create the PATH if it does not already ** exist. Overwrite existing values that do exist. ** If JSON is ill-formed, return NULL. ** ** json_insert(JSON, PATH, VALUE, ...) ** ** Create PATH and initialize it to VALUE. If PATH already exists, this ** routine is a no-op. If JSON is ill-formed, return NULL. */ static void jsonSetFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ JsonNode *pNode; const char *zPath; u32 i; int bApnd; int bIsSet = *(int*)sqlite3_user_data(ctx); if( argc<1 ) return; if( (argc&1)==0 ) { jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert"); return; } if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( x.nNode ){ for(i=1; i<(u32)argc; i+=2){ u8 jnFlags = JNODE_REPLACE; zPath = (const char*)sqlite3_value_text(argv[i]); if( zPath==0 ) continue; if( zPath[0]!='$' ) continue; if( zPath[1]=='$' ){ zPath++; jnFlags = JNODE_REPLACE|JNODE_JSON; } bApnd = 0; pNode = jsonLookup(&x, 0, &zPath[1], &bApnd); if( x.oom ){ sqlite3_result_error_nomem(ctx); goto jsonSetDone; }else if( pNode && (bApnd || bIsSet) ){ pNode->jnFlags &= ~JNODE_JSON; pNode->jnFlags |= jnFlags; pNode->iVal = i+1; } } if( x.aNode[0].jnFlags & JNODE_REPLACE ){ sqlite3_result_value(ctx, argv[x.aNode[0].iVal]); }else{ jsonReturn(x.aNode, ctx, argv); } } jsonSetDone: jsonParseReset(&x); } /* ** json_type(JSON) ** json_type(JSON, PATH) ** ** Return the top-level "type" of a JSON string. Return NULL if the ** input is not a well-formed JSON string. */ static void jsonTypeFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ const char *zPath; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 ) return; if( zPath[0]!='$' ) return; zPath++; }else{ zPath = 0; } if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; if( x.nNode ){ JsonNode *pNode = x.aNode; if( zPath ) pNode = jsonLookup(&x, 0, zPath, 0); if( pNode ){ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } } jsonParseReset(&x); } /* ** json_valid(JSON) ** ** Return 1 if JSON is a valid JSON string. Return 0 otherwise. */ static void jsonValidFunc( sqlite3_context *ctx, int argc, sqlite3_value **argv ){ JsonParse x; /* The parse */ int rc = 0; if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0]))==0 && x.nNode>0 ){ rc = 1; } jsonParseReset(&x); sqlite3_result_int(ctx, rc); } /**************************************************************************** ** The json_each virtual table ****************************************************************************/ typedef struct JsonEachCursor JsonEachCursor; struct JsonEachCursor { sqlite3_vtab_cursor base; /* Base class - must be first */ u32 iRowid; /* The rowid */ u32 i; /* Index in sParse.aNode[] of current row */ u32 iEnd; /* EOF when i equals or exceeds this value */ u8 eType; /* Type of top-level element */ u8 bRecursive; /* True for json_tree(). False for json_each() */ char *zJson; /* Input JSON */ char *zPath; /* Path by which to filter zJson */ JsonParse sParse; /* Parse of the input JSON */ }; /* Constructor for the json_each virtual table */ static int jsonEachConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define JEACH_KEY 0 #define JEACH_VALUE 1 #define JEACH_TYPE 2 #define JEACH_ATOM 3 #define JEACH_ID 4 #define JEACH_PARENT 5 #define JEACH_FULLKEY 6 #define JEACH_JSON 7 #define JEACH_PATH 8 UNUSED_PARAM(pzErr); UNUSED_PARAM(argv); UNUSED_PARAM(argc); UNUSED_PARAM(pAux); rc = sqlite3_declare_vtab(db, "CREATE TABLE x(key,value,type,atom,id,parent,fullkey," "json HIDDEN,path HIDDEN)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } return rc; } /* destructor for json_each virtual table */ static int jsonEachDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_each(). */ static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ JsonEachCursor *pCur; UNUSED_PARAM(p); pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* constructor for a JsonEachCursor object for json_tree(). */ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ int rc = jsonEachOpenEach(p, ppCursor); if( rc==SQLITE_OK ){ JsonEachCursor *pCur = (JsonEachCursor*)*ppCursor; pCur->bRecursive = 1; } return rc; } /* Reset a JsonEachCursor back to its original state. Free any memory ** held. */ static void jsonEachCursorReset(JsonEachCursor *p){ sqlite3_free(p->zJson); sqlite3_free(p->zPath); jsonParseReset(&p->sParse); p->iRowid = 0; p->i = 0; p->iEnd = 0; p->eType = 0; p->zJson = 0; p->zPath = 0; } /* Destructor for a jsonEachCursor object */ static int jsonEachClose(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; jsonEachCursorReset(p); sqlite3_free(cur); return SQLITE_OK; } /* Return TRUE if the jsonEachCursor object has been advanced off the end ** of the JSON object */ static int jsonEachEof(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; return p->i >= p->iEnd; } /* Advance the cursor to the next element for json_tree() */ static int jsonEachNext(sqlite3_vtab_cursor *cur){ JsonEachCursor *p = (JsonEachCursor*)cur; if( p->bRecursive ){ if( p->i==0 ){ p->i = 1; }else{ u32 iUp = p->sParse.aUp[p->i]; JsonNode *pUp = &p->sParse.aNode[iUp]; p->i++; if( pUp->eType==JSON_OBJECT && (pUp->n + iUp >= p->i) ) p->i++; } p->iRowid++; if( p->i<p->sParse.nNode ){ u32 iUp = p->sParse.aUp[p->i]; JsonNode *pUp = &p->sParse.aNode[iUp]; p->eType = pUp->eType; if( pUp->eType==JSON_ARRAY ){ if( iUp==p->i-1 ){ pUp->u.iKey = 0; }else{ pUp->u.iKey++; } } } }else{ switch( p->eType ){ case JSON_ARRAY: { p->i += jsonNodeSize(&p->sParse.aNode[p->i]); p->iRowid++; break; } case JSON_OBJECT: { p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]); p->iRowid++; break; } default: { p->i = p->iEnd; break; } } } return SQLITE_OK; } /* Append the name of the path for element i to pStr */ static void jsonEachComputePath( JsonEachCursor *p, /* The cursor */ JsonString *pStr, /* Write the path here */ u32 i /* Path to this element */ ){ JsonNode *pNode, *pUp; u32 iUp; if( i==0 ){ jsonAppendChar(pStr, '$'); return; } iUp = p->sParse.aUp[i]; jsonEachComputePath(p, pStr, iUp); pNode = &p->sParse.aNode[i]; pUp = &p->sParse.aNode[iUp]; if( pUp->eType==JSON_ARRAY ){ jsonPrintf(30, pStr, "[%d]", pUp->u.iKey); }else{ assert( pUp->eType==JSON_OBJECT ); if( pNode->eType>=JSON_ARRAY ) pNode--; assert( pNode->eType==JSON_STRING ); jsonPrintf(pNode->n+1, pStr, ".%.*s", pNode->n-2, pNode->u.zJContent+1); } } /* Return the value of a column */ static int jsonEachColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ JsonEachCursor *p = (JsonEachCursor*)cur; JsonNode *pThis = &p->sParse.aNode[p->i]; switch( i ){ case JEACH_KEY: { if( p->i==0 ) break; if( p->eType==JSON_OBJECT ){ jsonReturn(pThis, ctx, 0); }else if( p->eType==JSON_ARRAY ){ u32 iKey; if( p->bRecursive ){ if( p->iRowid==0 ) break; iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey; }else{ iKey = p->iRowid; } sqlite3_result_int64(ctx, (sqlite3_int64)iKey); } break; } case JEACH_VALUE: { if( p->eType==JSON_OBJECT && p->i>0 ) pThis++; jsonReturn(pThis, ctx, 0); break; } case JEACH_TYPE: { if( p->eType==JSON_OBJECT && p->i>0 ) pThis++; sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC); break; } case JEACH_ATOM: { if( p->eType==JSON_OBJECT && p->i>0 ) pThis++; if( pThis->eType>=JSON_ARRAY ) break; jsonReturn(pThis, ctx, 0); break; } case JEACH_ID: { sqlite3_result_int64(ctx, (sqlite3_int64)p->i + (p->eType==JSON_OBJECT)); break; } case JEACH_PARENT: { if( p->i>0 && p->bRecursive ){ sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]); } break; } case JEACH_FULLKEY: { JsonString x; jsonInit(&x, ctx); if( p->bRecursive ){ jsonEachComputePath(p, &x, p->i); }else{ if( p->zPath ){ jsonAppendRaw(&x, p->zPath, (int)strlen(p->zPath)); }else{ jsonAppendChar(&x, '$'); } if( p->eType==JSON_ARRAY ){ jsonPrintf(30, &x, "[%d]", p->iRowid); }else{ jsonPrintf(pThis->n, &x, ".%.*s", pThis->n-2, pThis->u.zJContent+1); } } jsonResult(&x); break; } case JEACH_PATH: { const char *zPath = p->zPath; if( zPath==0 ){ if( p->bRecursive ){ JsonString x; jsonInit(&x, ctx); jsonEachComputePath(p, &x, p->sParse.aUp[p->i]); jsonResult(&x); break; } zPath = "$"; } sqlite3_result_text(ctx, zPath, -1, SQLITE_STATIC); break; } default: { assert( i==JEACH_JSON ); sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC); break; } } return SQLITE_OK; } /* Return the current rowid value */ static int jsonEachRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ JsonEachCursor *p = (JsonEachCursor*)cur; *pRowid = p->iRowid; return SQLITE_OK; } /* The query strategy is to look for an equality constraint on the json ** column. Without such a constraint, the table cannot operate. idxNum is ** 1 if the constraint is found, 3 if the constraint and zPath are found, ** and 0 otherwise. */ static int jsonEachBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; int jsonIdx = -1; int pathIdx = -1; const struct sqlite3_index_constraint *pConstraint; UNUSED_PARAM(tab); pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; switch( pConstraint->iColumn ){ case JEACH_JSON: jsonIdx = i; break; case JEACH_PATH: pathIdx = i; break; default: /* no-op */ break; } } if( jsonIdx<0 ){ pIdxInfo->idxNum = 0; pIdxInfo->estimatedCost = 1e99; }else{ pIdxInfo->estimatedCost = 1.0; pIdxInfo->aConstraintUsage[jsonIdx].argvIndex = 1; pIdxInfo->aConstraintUsage[jsonIdx].omit = 1; if( pathIdx<0 ){ pIdxInfo->idxNum = 1; }else{ pIdxInfo->aConstraintUsage[pathIdx].argvIndex = 2; pIdxInfo->aConstraintUsage[pathIdx].omit = 1; pIdxInfo->idxNum = 3; } } return SQLITE_OK; } /* Start a search on a new JSON string */ static int jsonEachFilter( sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ JsonEachCursor *p = (JsonEachCursor*)cur; const char *z; const char *zPath; sqlite3_int64 n; UNUSED_PARAM(idxStr); UNUSED_PARAM(argc); jsonEachCursorReset(p); if( idxNum==0 ) return SQLITE_OK; z = (const char*)sqlite3_value_text(argv[0]); if( z==0 ) return SQLITE_OK; if( idxNum&2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); if( zPath==0 || zPath[0]!='$' ) return SQLITE_OK; } n = sqlite3_value_bytes(argv[0]); p->zJson = sqlite3_malloc64( n+1 ); if( p->zJson==0 ) return SQLITE_NOMEM; memcpy(p->zJson, z, (size_t)n+1); if( jsonParse(&p->sParse, 0, p->zJson) || (p->bRecursive && jsonParseFindParents(&p->sParse)) ){ jsonEachCursorReset(p); }else{ JsonNode *pNode; if( idxNum==3 ){ p->bRecursive = 0; n = sqlite3_value_bytes(argv[1]); p->zPath = sqlite3_malloc64( n+1 ); if( p->zPath==0 ) return SQLITE_NOMEM; memcpy(p->zPath, zPath, (size_t)n+1); pNode = jsonLookup(&p->sParse, 0, p->zPath+1, 0); if( pNode==0 ){ jsonEachCursorReset(p); return SQLITE_OK; } }else{ pNode = p->sParse.aNode; } p->i = (int)(pNode - p->sParse.aNode); p->eType = pNode->eType; if( p->eType>=JSON_ARRAY ){ pNode->u.iKey = 0; p->iEnd = p->i + pNode->n + 1; if( !p->bRecursive ) p->i++; }else{ p->iEnd = p->i+1; } } return p->sParse.oom ? SQLITE_NOMEM : SQLITE_OK; } /* The methods of the json_each virtual table */ static sqlite3_module jsonEachModule = { 0, /* iVersion */ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ jsonEachOpenEach, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; /* The methods of the json_tree virtual table. */ static sqlite3_module jsonTreeModule = { 0, /* iVersion */ 0, /* xCreate */ jsonEachConnect, /* xConnect */ jsonEachBestIndex, /* xBestIndex */ jsonEachDisconnect, /* xDisconnect */ 0, /* xDestroy */ jsonEachOpenTree, /* xOpen - open a cursor */ jsonEachClose, /* xClose - close a cursor */ jsonEachFilter, /* xFilter - configure scan constraints */ jsonEachNext, /* xNext - advance a cursor */ jsonEachEof, /* xEof - check for end of scan */ jsonEachColumn, /* xColumn - read data */ jsonEachRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ 0, /* xSavepoint */ 0, /* xRelease */ 0 /* xRollbackTo */ }; /**************************************************************************** ** The following routine is the only publically visible identifier in this ** file. Call the following routine in order to register the various SQL ** functions and the virtual table implemented by this file. ****************************************************************************/ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_json_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; unsigned int i; static const struct { const char *zName; int nArg; int flag; void (*xFunc)(sqlite3_context*,int,sqlite3_value**); } aFunc[] = { { "json_array", -1, 0, jsonArrayFunc }, { "json_array_length", 1, 0, jsonArrayLengthFunc }, { "json_array_length", 2, 0, jsonArrayLengthFunc }, { "json_check", 1, 0, jsonCheckFunc }, { "json_extract", 2, 0, jsonExtractFunc }, { "json_insert", -1, 0, jsonSetFunc }, { "json_object", -1, 0, jsonObjectFunc }, { "json_remove", -1, 0, jsonRemoveFunc }, { "json_replace", -1, 0, jsonReplaceFunc }, { "json_set", -1, 1, jsonSetFunc }, { "json_type", 1, 0, jsonTypeFunc }, { "json_type", 2, 0, jsonTypeFunc }, { "json_valid", 1, 0, jsonValidFunc }, #if SQLITE_DEBUG /* DEBUG and TESTING functions */ { "json_parse", 1, 0, jsonParseFunc }, { "json_test1", 1, 0, jsonTest1Func }, { "json_nodecount", 1, 0, jsonNodeCountFunc }, #endif }; static const struct { const char *zName; sqlite3_module *pModule; } aMod[] = { { "json_each", &jsonEachModule }, { "json_tree", &jsonTreeModule }, }; SQLITE_EXTENSION_INIT2(pApi); (void)pzErrMsg; /* Unused parameter */ for(i=0; i<sizeof(aFunc)/sizeof(aFunc[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_function(db, aFunc[i].zName, aFunc[i].nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, (void*)&aFunc[i].flag, aFunc[i].xFunc, 0, 0); } for(i=0; i<sizeof(aMod)/sizeof(aMod[0]) && rc==SQLITE_OK; i++){ rc = sqlite3_create_module(db, aMod[i].zName, aMod[i].pModule, 0); } return rc; } |
Added ext/misc/series.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | /* ** 2015-08-18 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file demonstrates how to create a table-valued-function using ** a virtual table. This demo implements the generate_series() function ** which gives similar results to the eponymous function in PostgreSQL. ** Examples: ** ** SELECT * FROM generate_series(0,100,5); ** ** The query above returns integers from 0 through 100 counting by steps ** of 5. ** ** SELECT * FROM generate_series(0,100); ** ** Integers from 0 through 100 with a step size of 1. ** ** SELECT * FROM generate_series(20) LIMIT 10; ** ** Integers 20 through 29. ** ** HOW IT WORKS ** ** The generate_series "function" is really a virtual table with the ** following schema: ** ** CREATE FUNCTION generate_series( ** value, ** start HIDDEN, ** stop HIDDEN, ** step HIDDEN ** ); ** ** Function arguments in queries against this virtual table are translated ** into equality constraints against successive hidden columns. In other ** words, the following pairs of queries are equivalent to each other: ** ** SELECT * FROM generate_series(0,100,5); ** SELECT * FROM generate_series WHERE start=0 AND stop=100 AND step=5; ** ** SELECT * FROM generate_series(0,100); ** SELECT * FROM generate_series WHERE start=0 AND stop=100; ** ** SELECT * FROM generate_series(20) LIMIT 10; ** SELECT * FROM generate_series WHERE start=20 LIMIT 10; ** ** The generate_series virtual table implementation leaves the xCreate method ** set to NULL. This means that it is not possible to do a CREATE VIRTUAL ** TABLE command with "generate_series" as the USING argument. Instead, there ** is a single generate_series virtual table that is always available without ** having to be created first. ** ** The xBestIndex method looks for equality constraints against the hidden ** start, stop, and step columns, and if present, it uses those constraints ** to bound the sequence of generated values. If the equality constraints ** are missing, it uses 0 for start, 4294967295 for stop, and 1 for step. ** xBestIndex returns a small cost when both start and stop are available, ** and a very large cost if either start or stop are unavailable. This ** encourages the query planner to order joins such that the bounds of the ** series are well-defined. */ #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 #include <assert.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE /* series_cursor is a subclass of sqlite3_vtab_cursor which will ** serve as the underlying representation of a cursor that scans ** over rows of the result */ typedef struct series_cursor series_cursor; struct series_cursor { sqlite3_vtab_cursor base; /* Base class - must be first */ int isDesc; /* True to count down rather than up */ sqlite3_int64 iRowid; /* The rowid */ sqlite3_int64 iValue; /* Current value ("value") */ sqlite3_int64 mnValue; /* Mimimum value ("start") */ sqlite3_int64 mxValue; /* Maximum value ("stop") */ sqlite3_int64 iStep; /* Increment ("step") */ }; /* ** The seriesConnect() method is invoked to create a new ** series_vtab that describes the generate_series virtual table. ** ** Think of this routine as the constructor for series_vtab objects. ** ** All this routine needs to do is: ** ** (1) Allocate the series_vtab object and initialize all fields. ** ** (2) Tell SQLite (via the sqlite3_declare_vtab() interface) what the ** result set of queries against generate_series will look like. */ static int seriesConnect( sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVtab, char **pzErr ){ sqlite3_vtab *pNew; int rc; /* Column numbers */ #define SERIES_COLUMN_VALUE 0 #define SERIES_COLUMN_START 1 #define SERIES_COLUMN_STOP 2 #define SERIES_COLUMN_STEP 3 rc = sqlite3_declare_vtab(db, "CREATE TABLE x(value,start hidden,stop hidden,step hidden)"); if( rc==SQLITE_OK ){ pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) ); if( pNew==0 ) return SQLITE_NOMEM; memset(pNew, 0, sizeof(*pNew)); } return rc; } /* ** This method is the destructor for series_cursor objects. */ static int seriesDisconnect(sqlite3_vtab *pVtab){ sqlite3_free(pVtab); return SQLITE_OK; } /* ** Constructor for a new series_cursor object. */ static int seriesOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ series_cursor *pCur; pCur = sqlite3_malloc( sizeof(*pCur) ); if( pCur==0 ) return SQLITE_NOMEM; memset(pCur, 0, sizeof(*pCur)); *ppCursor = &pCur->base; return SQLITE_OK; } /* ** Destructor for a series_cursor. */ static int seriesClose(sqlite3_vtab_cursor *cur){ sqlite3_free(cur); return SQLITE_OK; } /* ** Advance a series_cursor to its next row of output. */ static int seriesNext(sqlite3_vtab_cursor *cur){ series_cursor *pCur = (series_cursor*)cur; if( pCur->isDesc ){ pCur->iValue -= pCur->iStep; }else{ pCur->iValue += pCur->iStep; } pCur->iRowid++; return SQLITE_OK; } /* ** Return values of columns for the row at which the series_cursor ** is currently pointing. */ static int seriesColumn( sqlite3_vtab_cursor *cur, /* The cursor */ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ int i /* Which column to return */ ){ series_cursor *pCur = (series_cursor*)cur; sqlite3_int64 x = 0; switch( i ){ case SERIES_COLUMN_START: x = pCur->mnValue; break; case SERIES_COLUMN_STOP: x = pCur->mxValue; break; case SERIES_COLUMN_STEP: x = pCur->iStep; break; default: x = pCur->iValue; break; } sqlite3_result_int64(ctx, x); return SQLITE_OK; } /* ** Return the rowid for the current row. In this implementation, the ** rowid is the same as the output value. */ static int seriesRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ series_cursor *pCur = (series_cursor*)cur; *pRowid = pCur->iRowid; return SQLITE_OK; } /* ** Return TRUE if the cursor has been moved off of the last ** row of output. */ static int seriesEof(sqlite3_vtab_cursor *cur){ series_cursor *pCur = (series_cursor*)cur; if( pCur->isDesc ){ return pCur->iValue < pCur->mnValue; }else{ return pCur->iValue > pCur->mxValue; } } /* ** This method is called to "rewind" the series_cursor object back ** to the first row of output. This method is always called at least ** once prior to any call to seriesColumn() or seriesRowid() or ** seriesEof(). ** ** The query plan selected by seriesBestIndex is passed in the idxNum ** parameter. (idxStr is not used in this implementation.) idxNum ** is a bitmask showing which constraints are available: ** ** 1: start=VALUE ** 2: stop=VALUE ** 4: step=VALUE ** ** Also, if bit 8 is set, that means that the series should be output ** in descending order rather than in ascending order. ** ** This routine should initialize the cursor and position it so that it ** is pointing at the first row, or pointing off the end of the table ** (so that seriesEof() will return true) if the table is empty. */ static int seriesFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv ){ series_cursor *pCur = (series_cursor *)pVtabCursor; int i = 0; if( idxNum & 1 ){ pCur->mnValue = sqlite3_value_int64(argv[i++]); }else{ pCur->mnValue = 0; } if( idxNum & 2 ){ pCur->mxValue = sqlite3_value_int64(argv[i++]); }else{ pCur->mxValue = 0xffffffff; } if( idxNum & 4 ){ pCur->iStep = sqlite3_value_int64(argv[i++]); if( pCur->iStep<1 ) pCur->iStep = 1; }else{ pCur->iStep = 1; } if( idxNum & 8 ){ pCur->isDesc = 1; pCur->iValue = pCur->mxValue; if( pCur->iStep>0 ){ pCur->iValue -= (pCur->mxValue - pCur->mnValue)%pCur->iStep; } }else{ pCur->isDesc = 0; pCur->iValue = pCur->mnValue; } pCur->iRowid = 1; return SQLITE_OK; } /* ** SQLite will invoke this method one or more times while planning a query ** that uses the generate_series virtual table. This routine needs to create ** a query plan for each invocation and compute an estimated cost for that ** plan. ** ** In this implementation idxNum is used to represent the ** query plan. idxStr is unused. ** ** The query plan is represented by bits in idxNum: ** ** (1) start = $value -- constraint exists ** (2) stop = $value -- constraint exists ** (4) step = $value -- constraint exists ** (8) output in descending order */ static int seriesBestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo ){ int i; /* Loop over constraints */ int idxNum = 0; /* The query plan bitmask */ int startIdx = -1; /* Index of the start= constraint, or -1 if none */ int stopIdx = -1; /* Index of the stop= constraint, or -1 if none */ int stepIdx = -1; /* Index of the step= constraint, or -1 if none */ int nArg = 0; /* Number of arguments that seriesFilter() expects */ const struct sqlite3_index_constraint *pConstraint; pConstraint = pIdxInfo->aConstraint; for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){ if( pConstraint->usable==0 ) continue; if( pConstraint->op!=SQLITE_INDEX_CONSTRAINT_EQ ) continue; switch( pConstraint->iColumn ){ case SERIES_COLUMN_START: startIdx = i; idxNum |= 1; break; case SERIES_COLUMN_STOP: stopIdx = i; idxNum |= 2; break; case SERIES_COLUMN_STEP: stepIdx = i; idxNum |= 4; break; } } if( startIdx>=0 ){ pIdxInfo->aConstraintUsage[startIdx].argvIndex = ++nArg; pIdxInfo->aConstraintUsage[startIdx].omit = 1; } if( stopIdx>=0 ){ pIdxInfo->aConstraintUsage[stopIdx].argvIndex = ++nArg; pIdxInfo->aConstraintUsage[stopIdx].omit = 1; } if( stepIdx>=0 ){ pIdxInfo->aConstraintUsage[stepIdx].argvIndex = ++nArg; pIdxInfo->aConstraintUsage[stepIdx].omit = 1; } if( (idxNum & 3)==3 ){ /* Both start= and stop= boundaries are available. This is the ** the preferred case */ pIdxInfo->estimatedCost = (double)1; pIdxInfo->estimatedRows = 1000; if( pIdxInfo->nOrderBy==1 ){ if( pIdxInfo->aOrderBy[0].desc ) idxNum |= 8; pIdxInfo->orderByConsumed = 1; } }else{ /* If either boundary is missing, we have to generate a huge span ** of numbers. Make this case very expensive so that the query ** planner will work hard to avoid it. */ pIdxInfo->estimatedCost = (double)2147483647; pIdxInfo->estimatedRows = 2147483647; } pIdxInfo->idxNum = idxNum; return SQLITE_OK; } /* ** This following structure defines all the methods for the ** generate_series virtual table. */ static sqlite3_module seriesModule = { 0, /* iVersion */ 0, /* xCreate */ seriesConnect, /* xConnect */ seriesBestIndex, /* xBestIndex */ seriesDisconnect, /* xDisconnect */ 0, /* xDestroy */ seriesOpen, /* xOpen - open a cursor */ seriesClose, /* xClose - close a cursor */ seriesFilter, /* xFilter - configure scan constraints */ seriesNext, /* xNext - advance a cursor */ seriesEof, /* xEof - check for end of scan */ seriesColumn, /* xColumn - read data */ seriesRowid, /* xRowid - read data */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindMethod */ 0, /* xRename */ }; #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifdef _WIN32 __declspec(dllexport) #endif int sqlite3_series_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ){ int rc = SQLITE_OK; SQLITE_EXTENSION_INIT2(pApi); #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3_libversion_number()<3008012 ){ *pzErrMsg = sqlite3_mprintf( "generate_series() requires SQLite 3.8.12 or later"); return SQLITE_ERROR; } rc = sqlite3_create_module(db, "generate_series", &seriesModule, 0); #endif return rc; } |
Added ext/rbu/rbusave.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # 2015 August 14 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source $testdir/tester.tcl set ::testprefix rbusave do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c) WITHOUT ROWID; CREATE TABLE t2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b); CREATE INDEX i2 ON t2(c, b); INSERT INTO t1 VALUES(1, 1, 1); INSERT INTO t1 VALUES(2, 2, 2); INSERT INTO t1 VALUES(3, 3, 3); INSERT INTO t2 VALUES(1, 1, 1); INSERT INTO t2 VALUES(2, 2, 2); INSERT INTO t2 VALUES(3, 3, 3); } do_test 1.1 { forcedelete test.db2 sqlite3 db2 test.db2 db2 eval { CREATE TABLE data_t1(a, b, c, rbu_control); INSERT INTO data_t1 VALUES(4, 4, 4, 0); INSERT INTO data_t1 VALUES(2, NULL, NULL, 1); INSERT INTO data_t1 VALUES(1, 'one', NULL, '.x.'); CREATE TABLE data_t2(a, b, c, rbu_control); INSERT INTO data_t2 VALUES(4, 4, 4, 0); INSERT INTO data_t2 VALUES(2, NULL, NULL, 1); INSERT INTO data_t2 VALUES(1, 'one', NULL, '.x.'); } } {} proc test_to_bak {} { foreach f { test.db test.db-wal test.db-oal test.db-journal test.db2 test.db2-wal test.db2-oal test.db2-journal } { set t [string map {test bak} $f] forcedelete $t if {[file exists $f]} { forcecopy $f $t } } } do_test 1.2 { test_to_bak sqlite3rbu rrr bak.db bak.db2 set nStep 0 while {[rrr step]=="SQLITE_OK"} {incr nStep} set res2 [rrr close] } {SQLITE_DONE} sqlite3rbu rbu test.db test.db2 set res "SQLITE_OK" for {set i 1} {$res=="SQLITE_OK"} {incr i} { set res [rbu step] do_test 1.3.$i.1 { rbu savestate test_to_bak sqlite3rbu rrr bak.db bak.db2 set nRem 0 while {[rrr step]=="SQLITE_OK"} {incr nRem} set res2 [rrr close] } {SQLITE_DONE} do_test 1.3.$i.3 { expr $nRem+$i } [expr {$nStep + ($res=="SQLITE_DONE")}] do_test 1.3.$i.3 { sqlite3 bak bak.db bak eval { SELECT * FROM t1; SELECT * FROM t2; } } {1 one 1 3 3 3 4 4 4 1 one 1 3 3 3 4 4 4} bak close } do_test 1.4 { rbu close } {SQLITE_DONE} do_execsql_test 1.5 { SELECT * FROM t1; SELECT * FROM t2; } {1 one 1 3 3 3 4 4 4 1 one 1 3 3 3 4 4 4} finish_test |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
80 81 82 83 84 85 86 | ** */ #include <assert.h> #include <string.h> #include <stdio.h> | < < < < | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | ** */ #include <assert.h> #include <string.h> #include <stdio.h> #include "sqlite3.h" #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) #include "sqlite3rbu.h" /* Maximum number of prepared UPDATE statements held by this module */ #define SQLITE_RBU_UPDATE_CACHESIZE 16 |
︙ | ︙ | |||
2924 2925 2926 2927 2928 2929 2930 | /* ** If there is a "*-oal" file in the file-system corresponding to the ** target database in the file-system, delete it. If an error occurs, ** leave an error code and error message in the rbu handle. */ static void rbuDeleteOalFile(sqlite3rbu *p){ | | > > | | | > | 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 | /* ** If there is a "*-oal" file in the file-system corresponding to the ** target database in the file-system, delete it. If an error occurs, ** leave an error code and error message in the rbu handle. */ static void rbuDeleteOalFile(sqlite3rbu *p){ char *zOal = rbuMPrintf(p, "%s-oal", p->zTarget); if( zOal ){ sqlite3_vfs *pVfs = sqlite3_vfs_find(0); assert( pVfs && p->rc==SQLITE_OK && p->zErrmsg==0 ); pVfs->xDelete(pVfs, zOal, 0); sqlite3_free(zOal); } } /* ** Allocate a private rbu VFS for the rbu handle passed as the only ** argument. This VFS will be used unless the call to sqlite3rbu_open() ** specified a URI with a vfs=? option in place of a target database ** file name. |
︙ | ︙ | |||
3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 | ** page 1 of the database file. */ p->rc = SQLITE_BUSY; p->zErrmsg = sqlite3_mprintf("database modified during rbu update"); } if( p->rc==SQLITE_OK ){ if( p->eStage==RBU_STAGE_OAL ){ /* Open transactions both databases. The *-oal file is opened or ** created at this point. */ | > | | > > > > > > > > > > | 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 | ** page 1 of the database file. */ p->rc = SQLITE_BUSY; p->zErrmsg = sqlite3_mprintf("database modified during rbu update"); } if( p->rc==SQLITE_OK ){ if( p->eStage==RBU_STAGE_OAL ){ sqlite3 *db = p->dbMain; /* Open transactions both databases. The *-oal file is opened or ** created at this point. */ p->rc = sqlite3_exec(db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); if( p->rc==SQLITE_OK ){ p->rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg); } /* Check if the main database is a zipvfs db. If it is, set the upper ** level pager to use "journal_mode=off". This prevents it from ** generating a large journal using a temp file. */ if( p->rc==SQLITE_OK ){ int frc = sqlite3_file_control(db, "main", SQLITE_FCNTL_ZIPVFS, 0); if( frc==SQLITE_OK ){ p->rc = sqlite3_exec(db, "PRAGMA journal_mode=off",0,0,&p->zErrmsg); } } /* Point the object iterator at the first object */ if( p->rc==SQLITE_OK ){ p->rc = rbuObjIterFirst(p, &p->objiter); } /* If the RBU database contains no data_xxx tables, declare the RBU ** update finished. */ |
︙ | ︙ | |||
3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 | ** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current RBU update was started. */ sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){ return pRbu->nProgress; } /************************************************************************** ** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour ** of a standard VFS in the following ways: ** ** 1. Whenever the first page of a main database file is read or ** written, the value of the change-counter cookie is stored in | > > > > > > > > > > > > > > > > > > > > > > > > > > | 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 | ** Return the total number of key-value operations (inserts, deletes or ** updates) that have been performed on the target database since the ** current RBU update was started. */ sqlite3_int64 sqlite3rbu_progress(sqlite3rbu *pRbu){ return pRbu->nProgress; } int sqlite3rbu_savestate(sqlite3rbu *p){ int rc = p->rc; if( rc==SQLITE_DONE ) return SQLITE_OK; assert( p->eStage>=RBU_STAGE_OAL && p->eStage<=RBU_STAGE_DONE ); if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0); } p->rc = rc; rbuSaveState(p, p->eStage); rc = p->rc; if( p->eStage==RBU_STAGE_OAL ){ assert( rc!=SQLITE_DONE ); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "COMMIT", 0, 0, 0); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbRbu, "BEGIN IMMEDIATE", 0, 0, 0); if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "BEGIN IMMEDIATE", 0, 0,0); } p->rc = rc; return rc; } /************************************************************************** ** Beginning of RBU VFS shim methods. The VFS shim modifies the behaviour ** of a standard VFS in the following ways: ** ** 1. Whenever the first page of a main database file is read or ** written, the value of the change-counter cookie is stored in |
︙ | ︙ |
Changes to ext/rbu/sqlite3rbu.h.
︙ | ︙ | |||
350 351 352 353 354 355 356 357 358 359 360 361 362 363 | ** ** Once a call to sqlite3rbu_step() has returned a value other than ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops ** that immediately return the same value. */ int sqlite3rbu_step(sqlite3rbu *pRbu); /* ** Close an RBU handle. ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the ** current state of the RBU update appliation to the RBU database. ** | > > > > > > > > > > > > | 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 | ** ** Once a call to sqlite3rbu_step() has returned a value other than ** SQLITE_OK, all subsequent calls on the same RBU handle are no-ops ** that immediately return the same value. */ int sqlite3rbu_step(sqlite3rbu *pRbu); /* ** Force RBU to save its state to disk. ** ** If a power failure or application crash occurs during an update, following ** system recovery RBU may resume the update from the point at which the state ** was last saved. In other words, from the most recent successful call to ** sqlite3rbu_close() or this function. ** ** SQLITE_OK is returned if successful, or an SQLite error code otherwise. */ int sqlite3rbu_savestate(sqlite3rbu *pRbu); /* ** Close an RBU handle. ** ** If the RBU update has been completely applied, mark the RBU database ** as fully applied. Otherwise, assuming no error has occurred, save the ** current state of the RBU update appliation to the RBU database. ** |
︙ | ︙ |
Changes to ext/rbu/test_rbu.c.
︙ | ︙ | |||
52 53 54 55 56 57 58 | ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ret = TCL_OK; sqlite3rbu *pRbu = (sqlite3rbu*)clientData; | | > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ int ret = TCL_OK; sqlite3rbu *pRbu = (sqlite3rbu*)clientData; const char *azMethod[] = { "step", "close", "create_rbu_delta", "savestate", 0 }; int iMethod; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "METHOD"); return TCL_ERROR; } if( Tcl_GetIndexFromObj(interp, objv[1], azMethod, "method", 0, &iMethod) ){ |
︙ | ︙ | |||
94 95 96 97 98 99 100 101 102 103 104 105 106 107 | } case 2: /* create_rbu_delta */ { sqlite3 *db = sqlite3rbu_db(pRbu, 0); int rc = sqlite3_create_function( db, "rbu_delta", -1, SQLITE_UTF8, (void*)interp, test_rbu_delta, 0, 0 ); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); break; } default: /* seems unlikely */ assert( !"cannot happen" ); | > > > > > > > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | } case 2: /* create_rbu_delta */ { sqlite3 *db = sqlite3rbu_db(pRbu, 0); int rc = sqlite3_create_function( db, "rbu_delta", -1, SQLITE_UTF8, (void*)interp, test_rbu_delta, 0, 0 ); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); break; } case 3: /* savestate */ { int rc = sqlite3rbu_savestate(pRbu); Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); break; } default: /* seems unlikely */ assert( !"cannot happen" ); |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/vfslog.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ fts5.c | > > | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | TESTSRC += \ $(TOP)/ext/misc/amatch.c \ $(TOP)/ext/misc/closure.c \ $(TOP)/ext/misc/eval.c \ $(TOP)/ext/misc/fileio.c \ $(TOP)/ext/misc/fuzzer.c \ $(TOP)/ext/misc/ieee754.c \ $(TOP)/ext/misc/json1.c \ $(TOP)/ext/misc/nextchar.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/vfslog.c \ $(TOP)/ext/fts5/fts5_tcl.c \ $(TOP)/ext/fts5/fts5_test_mi.c \ fts5.c |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
352 353 354 355 356 357 358 359 360 361 362 363 364 365 | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ const char *zMsg = isView ? "no such view" : "no such table"; if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } | > > > > > > > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ return 0; } p = sqlite3FindTable(pParse->db, zName, zDbase); if( p==0 ){ const char *zMsg = isView ? "no such view" : "no such table"; #ifndef SQLITE_OMIT_VIRTUAL_TABLE /* If zName is the not the name of a table in the schema created using ** CREATE, then check to see if it is the name of an virtual table that ** can be an eponymous virtual table. */ Module *pMod = (Module*)sqlite3HashFind(&pParse->db->aModule, zName); if( pMod && sqlite3VtabEponymousTableInit(pParse, pMod) ){ return pMod->pEpoTab; } #endif if( zDbase ){ sqlite3ErrorMsg(pParse, "%s: %s.%s", zMsg, zDbase, zName); }else{ sqlite3ErrorMsg(pParse, "%s: %s", zMsg, zName); } pParse->checkSchema = 1; } |
︙ | ︙ | |||
556 557 558 559 560 561 562 | db->flags &= ~SQLITE_InternChanges; } /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ | | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 | db->flags &= ~SQLITE_InternChanges; } /* ** Delete memory allocated for the column names of a table or view (the ** Table.aCol[] array). */ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){ int i; Column *pCol; assert( pTable!=0 ); if( (pCol = pTable->aCol)!=0 ){ for(i=0; i<pTable->nCol; i++, pCol++){ sqlite3DbFree(db, pCol->zName); sqlite3ExprDelete(db, pCol->pDflt); |
︙ | ︙ | |||
623 624 625 626 627 628 629 | } /* Delete any foreign keys attached to this table. */ sqlite3FkDelete(db, pTable); /* Delete the Table structure itself. */ | | < < | 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 | } /* Delete any foreign keys attached to this table. */ sqlite3FkDelete(db, pTable); /* Delete the Table structure itself. */ sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); sqlite3SelectDelete(db, pTable->pSelect); sqlite3ExprListDelete(db, pTable->pCheck); #ifndef SQLITE_OMIT_VIRTUALTABLE sqlite3VtabClear(db, pTable); #endif sqlite3DbFree(db, pTable); /* Verify that no lookaside memory was used by schema tables */ assert( nLookaside==0 || nLookaside==db->lookaside.nOut ); |
︙ | ︙ | |||
1297 1298 1299 1300 1301 1302 1303 | iCol = pTab->nCol - 1; pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; zType = pTab->aCol[iCol].zType; nTerm = 1; }else{ nTerm = pList->nExpr; for(i=0; i<nTerm; i++){ | > > > | | | | | > | | 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 | iCol = pTab->nCol - 1; pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; zType = pTab->aCol[iCol].zType; nTerm = 1; }else{ nTerm = pList->nExpr; for(i=0; i<nTerm; i++){ Expr *pCExpr = sqlite3ExprSkipCollate(pList->a[i].pExpr); if( pCExpr && pCExpr->op==TK_ID ){ const char *zCName = pCExpr->u.zToken; for(iCol=0; iCol<pTab->nCol; iCol++){ if( sqlite3StrICmp(zCName, pTab->aCol[iCol].zName)==0 ){ pTab->aCol[iCol].colFlags |= COLFLAG_PRIMKEY; zType = pTab->aCol[iCol].zType; break; } } } } } if( nTerm==1 && zType && sqlite3StrICmp(zType, "INTEGER")==0 && sortOrder!=SQLITE_SO_DESC ){ pTab->iPKey = iCol; pTab->keyConf = (u8)onError; assert( autoInc==0 || autoInc==1 ); pTab->tabFlags |= autoInc*TF_Autoincrement; if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder; }else if( autoInc ){ |
︙ | ︙ | |||
1683 1684 1685 1686 1687 1688 1689 | } /* Locate the PRIMARY KEY index. Or, if this table was originally ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. */ if( pTab->iPKey>=0 ){ ExprList *pList; | > > > | > < < | 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 | } /* Locate the PRIMARY KEY index. Or, if this table was originally ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. */ if( pTab->iPKey>=0 ){ ExprList *pList; Token ipkToken; ipkToken.z = pTab->aCol[pTab->iPKey].zName; ipkToken.n = sqlite3Strlen30(ipkToken.z); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &ipkToken, 0)); if( pList==0 ) return; pList->a[0].sortOrder = pParse->iPkSortOrder; assert( pParse->pNewTable==pTab ); pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0); if( pPk==0 ) return; pPk->idxType = SQLITE_IDXTYPE_PRIMARYKEY; pTab->iPKey = -1; }else{ |
︙ | ︙ | |||
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 | ** The parser calls this routine in order to create a new VIEW */ void sqlite3CreateView( Parse *pParse, /* The parsing context */ Token *pBegin, /* The CREATE token that begins the statement */ Token *pName1, /* The token that holds the name of the view */ Token *pName2, /* The token that holds the name of the view */ Select *pSelect, /* A SELECT statement that will become the new view */ int isTemp, /* TRUE for a TEMPORARY view */ int noErr /* Suppress error messages if VIEW already exists */ ){ Table *p; int n; const char *z; Token sEnd; DbFixer sFix; Token *pName = 0; int iDb; sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); sqlite3SelectDelete(db, pSelect); return; } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; | > | < < < | < < < | | < < > | > | > > > > > | 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 | ** The parser calls this routine in order to create a new VIEW */ void sqlite3CreateView( Parse *pParse, /* The parsing context */ Token *pBegin, /* The CREATE token that begins the statement */ Token *pName1, /* The token that holds the name of the view */ Token *pName2, /* The token that holds the name of the view */ ExprList *pCNames, /* Optional list of view column names */ Select *pSelect, /* A SELECT statement that will become the new view */ int isTemp, /* TRUE for a TEMPORARY view */ int noErr /* Suppress error messages if VIEW already exists */ ){ Table *p; int n; const char *z; Token sEnd; DbFixer sFix; Token *pName = 0; int iDb; sqlite3 *db = pParse->db; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); sqlite3SelectDelete(db, pSelect); return; } sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr); p = pParse->pNewTable; if( p==0 || pParse->nErr ) goto create_view_fail; sqlite3TwoPartName(pParse, pName1, pName2, &pName); iDb = sqlite3SchemaToIndex(db, p->pSchema); sqlite3FixInit(&sFix, pParse, iDb, "view", pName); if( sqlite3FixSelect(&sFix, pSelect) ) goto create_view_fail; /* Make a copy of the entire SELECT statement that defines the view. ** This will force all the Expr.token.z values to be dynamically ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ p->pSelect = sqlite3SelectDup(db, pSelect, EXPRDUP_REDUCE); p->pCheck = sqlite3ExprListDup(db, pCNames, EXPRDUP_REDUCE); if( db->mallocFailed ) goto create_view_fail; /* Locate the end of the CREATE VIEW statement. Make sEnd point to ** the end. */ sEnd = pParse->sLastToken; assert( sEnd.z[0]!=0 ); if( sEnd.z[0]!=';' ){ sEnd.z += sEnd.n; } sEnd.n = 0; n = (int)(sEnd.z - pBegin->z); assert( n>0 ); z = pBegin->z; while( sqlite3Isspace(z[n-1]) ){ n--; } sEnd.z = &z[n-1]; sEnd.n = 1; /* Use sqlite3EndTable() to add the view to the SQLITE_MASTER table */ sqlite3EndTable(pParse, 0, &sEnd, 0, 0); create_view_fail: sqlite3SelectDelete(db, pSelect); sqlite3ExprListDelete(db, pCNames); return; } #endif /* SQLITE_OMIT_VIEW */ #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) /* ** The Table structure pTable is really a VIEW. Fill in the names of ** the columns of the view in the pTable structure. Return the number ** of errors. If an error is seen leave an error message in pParse->zErrMsg. */ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ Table *pSelTab; /* A fake table from which we get the result set */ Select *pSel; /* Copy of the SELECT that implements the view */ int nErr = 0; /* Number of errors encountered */ int n; /* Temporarily holds the number of cursors assigned */ sqlite3 *db = pParse->db; /* Database connection for malloc errors */ sqlite3_xauth xAuth; /* Saved xAuth pointer */ u8 bEnabledLA; /* Saved db->lookaside.bEnabled state */ assert( pTable ); #ifndef SQLITE_OMIT_VIRTUALTABLE if( sqlite3VtabCallConnect(pParse, pTable) ){ return SQLITE_ERROR; } |
︙ | ︙ | |||
2164 2165 2166 2167 2168 2169 2170 | ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); | > > > > > > | | < | | | | | | | | | < | | | | | | | | | < | | | | | | | | > > > | | 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 | ** Note that the call to sqlite3ResultSetOfSelect() will expand any ** "*" elements in the results set of the view and will assign cursors ** to the elements of the FROM clause. But we do not want these changes ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); bEnabledLA = db->lookaside.bEnabled; if( pTable->pCheck ){ db->lookaside.bEnabled = 0; sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); }else{ pSel = sqlite3SelectDup(db, pTable->pSelect, 0); if( pSel ){ n = pParse->nTab; sqlite3SrcListAssignCursors(pParse, pSel->pSrc); pTable->nCol = -1; db->lookaside.bEnabled = 0; #ifndef SQLITE_OMIT_AUTHORIZATION xAuth = db->xAuth; db->xAuth = 0; pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); db->xAuth = xAuth; #else pSelTab = sqlite3ResultSetOfSelect(pParse, pSel); #endif pParse->nTab = n; if( pSelTab ){ assert( pTable->aCol==0 ); pTable->nCol = pSelTab->nCol; pTable->aCol = pSelTab->aCol; pSelTab->nCol = 0; pSelTab->aCol = 0; sqlite3DeleteTable(db, pSelTab); assert( sqlite3SchemaMutexHeld(db, 0, pTable->pSchema) ); }else{ pTable->nCol = 0; nErr++; } sqlite3SelectDelete(db, pSel); } else { nErr++; } } db->lookaside.bEnabled = bEnabledLA; pTable->pSchema->schemaFlags |= DB_UnresetViews; #endif /* SQLITE_OMIT_VIEW */ return nErr; } #endif /* !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) */ #ifndef SQLITE_OMIT_VIEW /* ** Clear the column names from every VIEW in database idx. */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; assert( sqlite3SchemaMutexHeld(db, idx, 0) ); if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ sqlite3DeleteColumnNames(db, pTab); pTab->aCol = 0; pTab->nCol = 0; } } DbClearProperty(db, idx, DB_UnresetViews); } #else |
︙ | ︙ | |||
3021 3022 3023 3024 3025 3026 3027 | #endif /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ | > > > | > | < | > > | < | 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 | #endif /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ Token prevCol; prevCol.z = pTab->aCol[pTab->nCol-1].zName; prevCol.n = sqlite3Strlen30(prevCol.z); pList = sqlite3ExprListAppend(pParse, 0, sqlite3ExprAlloc(db, TK_ID, &prevCol, 0)); if( pList==0 ) goto exit_create_index; assert( pList->nExpr==1 ); sqlite3ExprListSetSortOrder(pList, sortOrder); }else{ sqlite3ExprListCheckLength(pParse, pList, "index"); } /* Figure out how many bytes of space are required to store explicitly ** specified collation sequence names. */ for(i=0; i<pList->nExpr; i++){ Expr *pExpr = pList->a[i].pExpr; if( pExpr && pExpr->op==TK_COLLATE ){ nExtra += (1 + sqlite3Strlen30(pExpr->u.zToken)); } } /* ** Allocate the index structure. */ |
︙ | ︙ | |||
3086 3087 3088 3089 3090 3091 3092 | ** TODO: Add a test to make sure that the same column is not named ** more than once within the same index. Only the first instance of ** the column will ever be used by the optimizer. Note that using the ** same column more than once cannot be an error because that would ** break backwards compatibility - it needs to be a warning. */ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ | | > > > > > > > | < | 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 | ** TODO: Add a test to make sure that the same column is not named ** more than once within the same index. Only the first instance of ** the column will ever be used by the optimizer. Note that using the ** same column more than once cannot be an error because that would ** break backwards compatibility - it needs to be a warning. */ for(i=0, pListItem=pList->a; i<pList->nExpr; i++, pListItem++){ const char *zColName; Expr *pCExpr; int requestedSortOrder; char *zColl; /* Collation sequence name */ pCExpr = sqlite3ExprSkipCollate(pListItem->pExpr); if( pCExpr->op!=TK_ID ){ sqlite3ErrorMsg(pParse, "indexes on expressions not yet supported"); continue; } zColName = pCExpr->u.zToken; for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){ if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; } if( j>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "table %s has no column named %s", pTab->zName, zColName); pParse->checkSchema = 1; goto exit_create_index; } assert( j<=0x7fff ); pIndex->aiColumn[i] = (i16)j; if( pListItem->pExpr->op==TK_COLLATE ){ int nColl; zColl = pListItem->pExpr->u.zToken; nColl = sqlite3Strlen30(zColl) + 1; assert( nExtra>=nColl ); memcpy(zExtra, zColl, nColl); zColl = zExtra; zExtra += nColl; nExtra -= nColl; |
︙ | ︙ | |||
3696 3697 3698 3699 3700 3701 3702 | int i; struct SrcList_item *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zAlias); | | > | 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 | int i; struct SrcList_item *pItem; if( pList==0 ) return; for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zAlias); if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); sqlite3DeleteTable(db, pItem->pTab); sqlite3SelectDelete(db, pItem->pSelect); sqlite3ExprDelete(db, pItem->pOn); sqlite3IdListDelete(db, pItem->pUsing); } sqlite3DbFree(db, pList); } |
︙ | ︙ | |||
3769 3770 3771 3772 3773 3774 3775 | ** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. */ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); if( p && ALWAYS(p->nSrc>0) ){ struct SrcList_item *pItem = &p->a[p->nSrc-1]; | | > > | | > > > > > > > > > > > > > > > > > > | | | 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 | ** Add an INDEXED BY or NOT INDEXED clause to the most recently added ** element of the source-list passed as the second argument. */ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); if( p && ALWAYS(p->nSrc>0) ){ struct SrcList_item *pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); if( pIndexedBy->n==1 && !pIndexedBy->z ){ /* A "NOT INDEXED" clause was supplied. See parse.y ** construct "indexed_opt" for details. */ pItem->fg.notIndexed = 1; }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy!=0); } } } /* ** Add the list of function arguments to the SrcList entry for a ** table-valued-function. */ void sqlite3SrcListFuncArgs(Parse *pParse, SrcList *p, ExprList *pList){ if( p && pList ){ struct SrcList_item *pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); pItem->u1.pFuncArg = pList; pItem->fg.isTabFunc = 1; }else{ sqlite3ExprListDelete(pParse->db, pList); } } /* ** When building up a FROM clause in the parser, the join operator ** is initially attached to the left operand. But the code generator ** expects the join operator to be on the right operand. This routine ** Shifts all join operators from left to right for an entire FROM ** clause. ** ** Example: Suppose the join is like this: ** ** A natural cross join B ** ** The operator is "natural cross join". The A and B operands are stored ** in p->a[0] and p->a[1], respectively. The parser initially stores the ** operator with A. This routine shifts that operator over to B. */ void sqlite3SrcListShiftJoinType(SrcList *p){ if( p ){ int i; for(i=p->nSrc-1; i>0; i--){ p->a[i].fg.jointype = p->a[i-1].fg.jointype; } p->a[0].fg.jointype = 0; } } /* ** Begin a transaction */ void sqlite3BeginTransaction(Parse *pParse, int type){ |
︙ | ︙ | |||
4295 4296 4297 4298 4299 4300 4301 | sqlite3SelectDelete(db, pQuery); sqlite3DbFree(db, zName); pNew = pWith; }else{ pNew->a[pNew->nCte].pSelect = pQuery; pNew->a[pNew->nCte].pCols = pArglist; pNew->a[pNew->nCte].zName = zName; | | | 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 | sqlite3SelectDelete(db, pQuery); sqlite3DbFree(db, zName); pNew = pWith; }else{ pNew->a[pNew->nCte].pSelect = pQuery; pNew->a[pNew->nCte].pCols = pArglist; pNew->a[pNew->nCte].zName = zName; pNew->a[pNew->nCte].zCteErr = 0; pNew->nCte++; } return pNew; } /* |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
439 440 441 442 443 444 445 | if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */ }else if( pPk ){ /* Construct a composite key for the row to be deleted and remember it */ iKey = ++pParse->nMem; nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, | | | 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen); addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */ }else if( pPk ){ /* Construct a composite key for the row to be deleted and remember it */ iKey = ++pParse->nMem; nKey = 0; /* Zero tells OP_Found to use a composite key */ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey, sqlite3IndexAffinityStr(pParse->db, pPk), nPk); sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey); }else{ /* Get the rowid of the row to be deleted and remember it in the RowSet */ nKey = 1; /* OP_Seek always uses a single rowid */ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey); } |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
429 430 431 432 433 434 435 | ** ** Construct a new expression node and return a pointer to it. Memory ** for this node and for the pToken argument is a single allocation ** obtained from sqlite3DbMalloc(). The calling function ** is responsible for making sure the node eventually gets freed. ** ** If dequote is true, then the token (if it exists) is dequoted. | | | 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 | ** ** Construct a new expression node and return a pointer to it. Memory ** for this node and for the pToken argument is a single allocation ** obtained from sqlite3DbMalloc(). The calling function ** is responsible for making sure the node eventually gets freed. ** ** If dequote is true, then the token (if it exists) is dequoted. ** If dequote is false, no dequoting is performed. The deQuote ** parameter is ignored if pToken is NULL or if the token does not ** appear to be quoted. If the quotes were of the form "..." (double-quotes) ** then the EP_DblQuoted flag is set on the expression node. ** ** Special case: If op==TK_INTEGER and pToken points to a string that ** can be translated into a 32-bit integer, then the token is not ** stored in u.zToken. Instead, the integer values is written |
︙ | ︙ | |||
1030 1031 1032 1033 1034 1035 1036 | struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); | | | < < | > | > | > > | 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 | struct SrcList_item *pNewItem = &pNew->a[i]; struct SrcList_item *pOldItem = &p->a[i]; Table *pTab; pNewItem->pSchema = pOldItem->pSchema; pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); pNewItem->fg = pOldItem->fg; pNewItem->iCursor = pOldItem->iCursor; pNewItem->addrFillSub = pOldItem->addrFillSub; pNewItem->regReturn = pOldItem->regReturn; if( pNewItem->fg.isIndexedBy ){ pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); } pNewItem->pIBIndex = pOldItem->pIBIndex; if( pNewItem->fg.isTabFunc ){ pNewItem->u1.pFuncArg = sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); } pTab = pNewItem->pTab = pOldItem->pTab; if( pTab ){ pTab->nRef++; } pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); pNewItem->pOn = sqlite3ExprDup(db, pOldItem->pOn, flags); pNewItem->pUsing = sqlite3IdListDup(db, pOldItem->pUsing); |
︙ | ︙ | |||
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 | no_mem: /* Avoid leaking memory if malloc has failed. */ sqlite3ExprDelete(db, pExpr); sqlite3ExprListDelete(db, pList); return 0; } /* ** Set the ExprList.a[].zName element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pName should never be ** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag | > > > > > > > > > > > > > > | 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 | no_mem: /* Avoid leaking memory if malloc has failed. */ sqlite3ExprDelete(db, pExpr); sqlite3ExprListDelete(db, pList); return 0; } /* ** Set the sort order for the last element on the given ExprList. */ void sqlite3ExprListSetSortOrder(ExprList *p, int iSortOrder){ if( p==0 ) return; assert( SQLITE_SO_UNDEFINED<0 && SQLITE_SO_ASC>=0 && SQLITE_SO_DESC>0 ); assert( p->nExpr>0 ); if( iSortOrder<0 ){ assert( p->a[p->nExpr-1].sortOrder==SQLITE_SO_ASC ); return; } p->a[p->nExpr-1].sortOrder = (u8)iSortOrder; } /* ** Set the ExprList.a[].zName element of the most recently added item ** on the expression list. ** ** pList might be NULL following an OOM error. But pName should never be ** NULL. If a memory allocation fails, the pParse->db->mallocFailed flag |
︙ | ︙ | |||
2892 2893 2894 2895 2896 2897 2898 | testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); pFarg->a[0].pExpr->op2 = pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ | | | 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 | testcase( pDef->funcFlags & OPFLAG_LENGTHARG ); pFarg->a[0].pExpr->op2 = pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG); } } sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */ sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR); sqlite3ExprCachePop(pParse); /* Ticket 2ea2425d34be */ }else{ r1 = 0; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* Possibly overload the function if the first argument is |
︙ | ︙ | |||
3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 | ** The SQLITE_ECEL_FACTOR argument allows constant arguments to be ** factored out into initialization code. */ int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* The expression list to be coded */ int target, /* Where to write results */ u8 flags /* SQLITE_ECEL_* flags */ ){ struct ExprList_item *pItem; | > | > > > | < | 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 | ** The SQLITE_ECEL_FACTOR argument allows constant arguments to be ** factored out into initialization code. */ int sqlite3ExprCodeExprList( Parse *pParse, /* Parsing context */ ExprList *pList, /* The expression list to be coded */ int target, /* Where to write results */ int srcReg, /* Source registers if SQLITE_ECEL_REF */ u8 flags /* SQLITE_ECEL_* flags */ ){ struct ExprList_item *pItem; int i, j, n; u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy; Vdbe *v = pParse->pVdbe; assert( pList!=0 ); assert( target>0 ); assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */ n = pList->nExpr; if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR; for(pItem=pList->a, i=0; i<n; i++, pItem++){ Expr *pExpr = pItem->pExpr; if( (flags & SQLITE_ECEL_REF)!=0 && (j = pList->a[i].u.x.iOrderByCol)>0 ){ sqlite3VdbeAddOp2(v, copyOp, j+srcReg-1, target+i); }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){ sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ VdbeOp *pOp; if( copyOp==OP_Copy && (pOp=sqlite3VdbeGetOp(v, -1))->opcode==OP_Copy && pOp->p1+pOp->p3+1==inReg && pOp->p2+pOp->p3+1==target+i ){ pOp->p3++; }else{ |
︙ | ︙ |
Changes to src/fkey.c.
︙ | ︙ | |||
412 413 414 415 416 417 418 | sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); } sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | sqlite3VdbeAddOp3(v, OP_Ne, iChild, iJump, iParent); VdbeCoverage(v); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); } sqlite3VdbeAddOp2(v, OP_Goto, 0, iOk); } sqlite3VdbeAddOp4(v, OP_MakeRecord, regTemp, nCol, regRec, sqlite3IndexAffinityStr(pParse->db,pIdx), nCol); sqlite3VdbeAddOp4Int(v, OP_Found, iCur, iOk, regRec, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempRange(pParse, regTemp, nCol); } } |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
65 66 67 68 69 70 71 | ** An extra 'D' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string ** is managed along with the rest of the Index structure. It will be ** released when sqlite3DeleteIndex() is called. */ | | < | 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 | ** An extra 'D' is appended to the end of the string to cover the ** rowid that appears as the last column in every index. ** ** Memory for the buffer containing the column index affinity string ** is managed along with the rest of the Index structure. It will be ** released when sqlite3DeleteIndex() is called. */ const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){ if( !pIdx->zColAff ){ /* The first time a column affinity string for a particular index is ** required, it is allocated and populated here. It is then stored as ** a member of the Index structure for subsequent use. ** ** The column affinity string will eventually be deleted by ** sqliteDeleteIndex() when the Index structure itself is cleaned ** up. */ int n; Table *pTab = pIdx->pTable; pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1); if( !pIdx->zColAff ){ db->mallocFailed = 1; return 0; } for(n=0; n<pIdx->nColumn; n++){ i16 x = pIdx->aiColumn[n]; |
︙ | ︙ | |||
701 702 703 704 705 706 707 | ** single-row VALUES clause */ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; srcTab = -1; assert( useTempTable==0 ); | > | < | > > | 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | ** single-row VALUES clause */ NameContext sNC; memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; srcTab = -1; assert( useTempTable==0 ); if( pList ){ nColumn = pList->nExpr; if( sqlite3ResolveExprListNames(&sNC, pList) ){ goto insert_cleanup; } }else{ nColumn = 0; } } /* If there is no IDLIST term but the table has an integer primary ** key, the set the ipkColumn variable to the integer primary key ** column index in the original table definition. */ |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
928 929 930 931 932 933 934 935 936 937 938 | /* ** Disconnect all sqlite3_vtab objects that belong to database connection ** db. This is called when db is being closed. */ static void disconnectAllVtab(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE int i; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( db->aDb[i].pSchema ){ | > < > > > > > > | 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 | /* ** Disconnect all sqlite3_vtab objects that belong to database connection ** db. This is called when db is being closed. */ static void disconnectAllVtab(sqlite3 *db){ #ifndef SQLITE_OMIT_VIRTUALTABLE int i; HashElem *p; sqlite3BtreeEnterAll(db); for(i=0; i<db->nDb; i++){ Schema *pSchema = db->aDb[i].pSchema; if( db->aDb[i].pSchema ){ for(p=sqliteHashFirst(&pSchema->tblHash); p; p=sqliteHashNext(p)){ Table *pTab = (Table *)sqliteHashData(p); if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } } for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ Module *pMod = (Module *)sqliteHashData(p); if( pMod->pEpoTab ){ sqlite3VtabDisconnect(db, pMod->pEpoTab); } } sqlite3VtabUnlockList(db); sqlite3BtreeLeaveAll(db); #else UNUSED_PARAMETER(db); #endif } |
︙ | ︙ | |||
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 | sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); if( pMod->xDestroy ){ pMod->xDestroy(pMod->pAux); } sqlite3DbFree(db, pMod); } sqlite3HashClear(&db->aModule); #endif sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); | > | 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 | sqlite3HashClear(&db->aCollSeq); #ifndef SQLITE_OMIT_VIRTUALTABLE for(i=sqliteHashFirst(&db->aModule); i; i=sqliteHashNext(i)){ Module *pMod = (Module *)sqliteHashData(i); if( pMod->xDestroy ){ pMod->xDestroy(pMod->pAux); } sqlite3VtabEponymousTableClear(db, pMod); sqlite3DbFree(db, pMod); } sqlite3HashClear(&db->aModule); #endif sqlite3Error(db, SQLITE_OK); /* Deallocates any cached error strings. */ sqlite3ValueFree(db->pErr); |
︙ | ︙ |
Changes to src/parse.y.
︙ | ︙ | |||
297 298 299 300 301 302 303 | // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);} ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);} | | | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 | // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} ccons ::= PRIMARY KEY sortorder(Z) onconf(R) autoinc(I). {sqlite3AddPrimaryKey(pParse,0,R,I,Z);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0,0,0);} ccons ::= CHECK LP expr(X) RP. {sqlite3AddCheckConstraint(pParse,X.pExpr);} ccons ::= REFERENCES nm(T) eidlist_opt(TA) refargs(R). {sqlite3CreateForeignKey(pParse,0,&T,TA,R);} ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE ids(C). {sqlite3AddCollateType(pParse, &C);} // The optional AUTOINCREMENT keyword %type autoinc {int} autoinc(X) ::= . {X = 0;} |
︙ | ︙ | |||
341 342 343 344 345 346 347 | conslist_opt(A) ::= . {A.n = 0; A.z = 0;} conslist_opt(A) ::= COMMA(X) conslist. {A = X;} conslist ::= conslist tconscomma tcons. conslist ::= tcons. tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} | | | | | | 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | conslist_opt(A) ::= . {A.n = 0; A.z = 0;} conslist_opt(A) ::= COMMA(X) conslist. {A = X;} conslist ::= conslist tconscomma tcons. conslist ::= tcons. tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= . tcons ::= CONSTRAINT nm(X). {pParse->constraintName = X;} tcons ::= PRIMARY KEY LP sortlist(X) autoinc(I) RP onconf(R). {sqlite3AddPrimaryKey(pParse,X,R,I,0);} tcons ::= UNIQUE LP sortlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0,0,0);} tcons ::= CHECK LP expr(E) RP onconf. {sqlite3AddCheckConstraint(pParse,E.pExpr);} tcons ::= FOREIGN KEY LP eidlist(FA) RP REFERENCES nm(T) eidlist_opt(TA) refargs(R) defer_subclause_opt(D). { sqlite3CreateForeignKey(pParse, FA, &T, TA, R); sqlite3DeferForeignKey(pParse, D); } %type defer_subclause_opt {int} defer_subclause_opt(A) ::= . {A = 0;} defer_subclause_opt(A) ::= defer_subclause(X). {A = X;} |
︙ | ︙ | |||
382 383 384 385 386 387 388 | %type ifexists {int} ifexists(A) ::= IF EXISTS. {A = 1;} ifexists(A) ::= . {A = 0;} ///////////////////// The CREATE VIEW statement ///////////////////////////// // %ifndef SQLITE_OMIT_VIEW | | > | | 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 | %type ifexists {int} ifexists(A) ::= IF EXISTS. {A = 1;} ifexists(A) ::= . {A = 0;} ///////////////////// The CREATE VIEW statement ///////////////////////////// // %ifndef SQLITE_OMIT_VIEW cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C) AS select(S). { sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E); } cmd ::= DROP VIEW ifexists(E) fullname(X). { sqlite3DropTable(pParse, X, 1, E); } %endif SQLITE_OMIT_VIEW //////////////////////// The SELECT statement ///////////////////////////////// |
︙ | ︙ | |||
582 583 584 585 586 587 588 | } // "seltablist" is a "Select Table List" - the content of the FROM clause // in a SELECT statement. "stl_prefix" is a prefix of this list. // stl_prefix(A) ::= seltablist(X) joinop(Y). { A = X; | | > > > > > | 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 | } // "seltablist" is a "Select Table List" - the content of the FROM clause // in a SELECT statement. "stl_prefix" is a prefix of this list. // stl_prefix(A) ::= seltablist(X) joinop(Y). { A = X; if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; } stl_prefix(A) ::= . {A = 0;} seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); sqlite3SrcListIndexedBy(pParse, A, &I); } seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); sqlite3SrcListFuncArgs(pParse, A, E); } %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U); } seltablist(A) ::= stl_prefix(X) LP seltablist(F) RP |
︙ | ︙ | |||
664 665 666 667 668 669 670 671 672 673 674 675 676 677 | %destructor using_opt {sqlite3IdListDelete(pParse->db, $$);} using_opt(U) ::= USING LP idlist(L) RP. {U = L;} using_opt(U) ::= . {U = 0;} %type orderby_opt {ExprList*} %destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);} %type sortlist {ExprList*} %destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);} orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} sortlist(A) ::= sortlist(X) COMMA expr(Y) sortorder(Z). { A = sqlite3ExprListAppend(pParse,X,Y.pExpr); | > > > > > | | | | 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 | %destructor using_opt {sqlite3IdListDelete(pParse->db, $$);} using_opt(U) ::= USING LP idlist(L) RP. {U = L;} using_opt(U) ::= . {U = 0;} %type orderby_opt {ExprList*} %destructor orderby_opt {sqlite3ExprListDelete(pParse->db, $$);} // the sortlist non-terminal stores a list of expression where each // expression is optionally followed by ASC or DESC to indicate the // sort order. // %type sortlist {ExprList*} %destructor sortlist {sqlite3ExprListDelete(pParse->db, $$);} orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} sortlist(A) ::= sortlist(X) COMMA expr(Y) sortorder(Z). { A = sqlite3ExprListAppend(pParse,X,Y.pExpr); sqlite3ExprListSetSortOrder(A,Z); } sortlist(A) ::= expr(Y) sortorder(Z). { A = sqlite3ExprListAppend(pParse,0,Y.pExpr); sqlite3ExprListSetSortOrder(A,Z); } %type sortorder {int} sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;} sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;} sortorder(A) ::= . {A = SQLITE_SO_UNDEFINED;} %type groupby_opt {ExprList*} %destructor groupby_opt {sqlite3ExprListDelete(pParse->db, $$);} groupby_opt(A) ::= . {A = 0;} groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;} %type having_opt {Expr*} |
︙ | ︙ | |||
775 776 777 778 779 780 781 | setlist(A) ::= nm(X) EQ expr(Y). { A = sqlite3ExprListAppend(pParse, 0, Y.pExpr); sqlite3ExprListSetName(pParse, A, &X, 1); } ////////////////////////// The INSERT command ///////////////////////////////// // | | | | | | | | 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 | setlist(A) ::= nm(X) EQ expr(Y). { A = sqlite3ExprListAppend(pParse, 0, Y.pExpr); sqlite3ExprListSetName(pParse, A, &X, 1); } ////////////////////////// The INSERT command ///////////////////////////////// // cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) select(S). { sqlite3WithPush(pParse, W, 1); sqlite3Insert(pParse, X, S, F, R); } cmd ::= with(W) insert_cmd(R) INTO fullname(X) idlist_opt(F) DEFAULT VALUES. { sqlite3WithPush(pParse, W, 1); sqlite3Insert(pParse, X, 0, F, R); } %type insert_cmd {u8} insert_cmd(A) ::= INSERT orconf(R). {A = R;} insert_cmd(A) ::= REPLACE. {A = OE_Replace;} %type idlist_opt {IdList*} %destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);} %type idlist {IdList*} %destructor idlist {sqlite3IdListDelete(pParse->db, $$);} idlist_opt(A) ::= . {A = 0;} idlist_opt(A) ::= LP idlist(X) RP. {A = X;} idlist(A) ::= idlist(X) COMMA nm(Y). {A = sqlite3IdListAppend(pParse->db,X,&Y);} idlist(A) ::= nm(Y). {A = sqlite3IdListAppend(pParse->db,0,&Y);} /////////////////////////// Expression Processing ///////////////////////////// // |
︙ | ︙ | |||
1198 1199 1200 1201 1202 1203 1204 | nexprlist(A) ::= expr(Y). {A = sqlite3ExprListAppend(pParse,0,Y.pExpr);} ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) | | > > > > > > > > > > > > > > > > | | | | < < < < > > > > > > > | > > > > > > > > > > > > | > > > | < > > > > | | < < < < | | | | 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 | nexprlist(A) ::= expr(Y). {A = sqlite3ExprListAppend(pParse,0,Y.pExpr);} ///////////////////////////// The CREATE INDEX command /////////////////////// // cmd ::= createkw(S) uniqueflag(U) INDEX ifnotexists(NE) nm(X) dbnm(D) ON nm(Y) LP sortlist(Z) RP where_opt(W). { sqlite3CreateIndex(pParse, &X, &D, sqlite3SrcListAppend(pParse->db,0,&Y,0), Z, U, &S, W, SQLITE_SO_ASC, NE); } %type uniqueflag {int} uniqueflag(A) ::= UNIQUE. {A = OE_Abort;} uniqueflag(A) ::= . {A = OE_None;} // The eidlist non-terminal (Expression Id List) generates an ExprList // from a list of identifiers. The identifier names are in ExprList.a[].zName. // This list is stored in an ExprList rather than an IdList so that it // can be easily sent to sqlite3ColumnsExprList(). // // eidlist is grouped with CREATE INDEX because it used to be the non-terminal // used for the arguments to an index. That is just an historical accident. // // IMPORTANT COMPATIBILITY NOTE: Some prior versions of SQLite accepted // COLLATE clauses and ASC or DESC keywords on ID lists in inappropriate // places - places that might have been stored in the sqlite_master schema. // Those extra features were ignored. But because they might be in some // (busted) old databases, we need to continue parsing them when loading // historical schemas. // %type eidlist {ExprList*} %destructor eidlist {sqlite3ExprListDelete(pParse->db, $$);} %type eidlist_opt {ExprList*} %destructor eidlist_opt {sqlite3ExprListDelete(pParse->db, $$);} %include { /* Add a single new term to an ExprList that is used to store a ** list of identifiers. Report an error if the ID list contains ** a COLLATE clause or an ASC or DESC keyword, except ignore the ** error while parsing a legacy schema. */ static ExprList *parserAddExprIdListTerm( Parse *pParse, ExprList *pPrior, Token *pIdToken, int hasCollate, int sortOrder ){ ExprList *p = sqlite3ExprListAppend(pParse, pPrior, 0); if( (hasCollate || sortOrder!=SQLITE_SO_UNDEFINED) && pParse->db->init.busy==0 ){ sqlite3ErrorMsg(pParse, "syntax error after column name \"%.*s\"", pIdToken->n, pIdToken->z); } sqlite3ExprListSetName(pParse, p, pIdToken, 1); return p; } } // end %include eidlist_opt(A) ::= . {A = 0;} eidlist_opt(A) ::= LP eidlist(X) RP. {A = X;} eidlist(A) ::= eidlist(X) COMMA nm(Y) collate(C) sortorder(Z). { A = parserAddExprIdListTerm(pParse, X, &Y, C, Z); } eidlist(A) ::= nm(Y) collate(C) sortorder(Z). { A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z); } %type collate {int} collate(C) ::= . {C = 0;} collate(C) ::= COLLATE ids. {C = 1;} ///////////////////////////// The DROP INDEX command ///////////////////////// // cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);} ///////////////////////////// The VACUUM command ///////////////////////////// |
︙ | ︙ | |||
1360 1361 1362 1363 1364 1365 1366 | %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z). { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); } // INSERT | | | 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 | %destructor trigger_cmd {sqlite3DeleteTriggerStep(pParse->db, $$);} // UPDATE trigger_cmd(A) ::= UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z). { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); } // INSERT trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S). {A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);} // DELETE trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y). {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);} // SELECT |
︙ | ︙ | |||
1480 1481 1482 1483 1484 1485 1486 | %destructor wqlist {sqlite3WithDelete(pParse->db, $$);} with(A) ::= . {A = 0;} %ifndef SQLITE_OMIT_CTE with(A) ::= WITH wqlist(W). { A = W; } with(A) ::= WITH RECURSIVE wqlist(W). { A = W; } | | | | 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 | %destructor wqlist {sqlite3WithDelete(pParse->db, $$);} with(A) ::= . {A = 0;} %ifndef SQLITE_OMIT_CTE with(A) ::= WITH wqlist(W). { A = W; } with(A) ::= WITH RECURSIVE wqlist(W). { A = W; } wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. { A = sqlite3WithAdd(pParse, 0, &X, Y, Z); } wqlist(A) ::= wqlist(W) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. { A = sqlite3WithAdd(pParse, W, &X, Y, Z); } %endif SQLITE_OMIT_CTE |
Changes to src/pcache1.c.
︙ | ︙ | |||
61 62 63 64 65 66 67 | ** SQLITE_CONFIG_PAGECACHE. ** (3) PCache-local bulk allocation. ** ** The third case is a chunk of heap memory (defaulting to 100 pages worth) ** that is allocated when the page cache is created. The size of the local ** bulk allocation can be adjusted using ** | | | 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | ** SQLITE_CONFIG_PAGECACHE. ** (3) PCache-local bulk allocation. ** ** The third case is a chunk of heap memory (defaulting to 100 pages worth) ** that is allocated when the page cache is created. The size of the local ** bulk allocation can be adjusted using ** ** sqlite3_config(SQLITE_CONFIG_PAGECACHE, 0, 0, N). ** ** If N is positive, then N pages worth of memory are allocated using a single ** sqlite3Malloc() call and that memory is used for the first N pages allocated. ** Or if N is negative, then -1024*N bytes of memory are allocated and used ** for as many pages as can be accomodated. ** ** Only one of (2) or (3) can be used. Once the memory available to (2) or |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
1338 1339 1340 1341 1342 1343 1344 | for(j=0; j<pFK->nCol; j++){ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } if( pParent ){ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, | | | 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 | for(j=0; j<pFK->nCol; j++){ sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j); sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v); } if( pParent ){ sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey, sqlite3IndexAffinityStr(db,pIdx), pFK->nCol); sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0); VdbeCoverage(v); } } sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1); sqlite3VdbeAddOp4(v, OP_String8, 0, regResult+2, 0, pFK->zTo, P4_TRANSIENT); |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
302 303 304 305 306 307 308 | for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ /* If there has been exactly one prior match and this match ** is for the right-hand table of a NATURAL JOIN or is in a ** USING clause, then skip this match. */ if( cnt==1 ){ | | | | | 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 | for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ /* If there has been exactly one prior match and this match ** is for the right-hand table of a NATURAL JOIN or is in a ** USING clause, then skip this match. */ if( cnt==1 ){ if( pItem->fg.jointype & JT_NATURAL ) continue; if( nameInUsingClause(pItem->pUsing, zCol) ) continue; } cnt++; pMatch = pItem; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j; break; } } } if( pMatch ){ pExpr->iTable = pMatch->iCursor; pExpr->pTab = pMatch->pTab; /* RIGHT JOIN not (yet) supported */ assert( (pMatch->fg.jointype & JT_RIGHT)==0 ); if( (pMatch->fg.jointype & JT_LEFT)!=0 ){ ExprSetProperty(pExpr, EP_CanBeNull); } pSchema = pExpr->pTab->pSchema; } } /* if( pSrcList ) */ #ifndef SQLITE_OMIT_TRIGGER |
︙ | ︙ | |||
403 404 405 406 407 408 409 | ** ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. ** ** The ability to use an output result-set column in the WHERE, GROUP BY, | | | | 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | ** ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. ** ** The ability to use an output result-set column in the WHERE, GROUP BY, ** or HAVING clauses, or as part of a larger expression in the ORDER BY ** clause is not standard SQL. This is a (goofy) SQLite extension, that ** is supported for backwards compatibility only. Hence, we issue a warning ** on sqlite3_log() whenever the capability is used. */ if( (pEList = pNC->pEList)!=0 && zTab==0 && cnt==0 ){ for(j=0; j<pEList->nExpr; j++){ |
︙ | ︙ | |||
1138 1139 1140 1141 1142 1143 1144 | */ static int resolveSelectStep(Walker *pWalker, Select *p){ NameContext *pOuterNC; /* Context that contains this SELECT */ NameContext sNC; /* Name context of this SELECT */ int isCompound; /* True if p is a compound select */ int nCompound; /* Number of compound terms processed so far */ Parse *pParse; /* Parsing context */ | < | 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 | */ static int resolveSelectStep(Walker *pWalker, Select *p){ NameContext *pOuterNC; /* Context that contains this SELECT */ NameContext sNC; /* Name context of this SELECT */ int isCompound; /* True if p is a compound select */ int nCompound; /* Number of compound terms processed so far */ Parse *pParse; /* Parsing context */ int i; /* Loop counter */ ExprList *pGroupBy; /* The GROUP BY clause */ Select *pLeftmost; /* Left-most of SELECT of a compound */ sqlite3 *db; /* Database connection */ assert( p!=0 ); |
︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 | int nRef = 0; /* Refcount for pOuterNC and outer contexts */ const char *zSavedContext = pParse->zAuthContext; /* Count the total number of references to pOuterNC and all of its ** parent contexts. After resolving references to expressions in ** pItem->pSelect, check if this value has changed. If so, then ** SELECT statement pItem->pSelect must be correlated. Set the | | | | < < < < | < < < | 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 | int nRef = 0; /* Refcount for pOuterNC and outer contexts */ const char *zSavedContext = pParse->zAuthContext; /* Count the total number of references to pOuterNC and all of its ** parent contexts. After resolving references to expressions in ** pItem->pSelect, check if this value has changed. If so, then ** SELECT statement pItem->pSelect must be correlated. Set the ** pItem->fg.isCorrelated flag if this is the case. */ for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef += pNC->nRef; if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; if( pParse->nErr || db->mallocFailed ) return WRC_Abort; for(pNC=pOuterNC; pNC; pNC=pNC->pNext) nRef -= pNC->nRef; assert( pItem->fg.isCorrelated==0 && nRef<=0 ); pItem->fg.isCorrelated = (nRef!=0); } } /* Set up the local name-context to pass to sqlite3ResolveExprNames() to ** resolve the result-set expression list. */ sNC.ncFlags = NC_AllowAgg; sNC.pSrcList = p->pSrc; sNC.pNext = pOuterNC; /* Resolve names in the result set. */ if( sqlite3ResolveExprListNames(&sNC, p->pEList) ) return WRC_Abort; /* If there are no aggregate functions in the result-set, and no GROUP BY ** expression, do not allow aggregates in any of the other expressions. */ assert( (p->selFlags & SF_Aggregate)==0 ); pGroupBy = p->pGroupBy; if( pGroupBy || (sNC.ncFlags & NC_HasAgg)!=0 ){ |
︙ | ︙ | |||
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 | ** ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ sNC.pEList = p->pEList; if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg; | > > > > > > > > > > | 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 | ** ** Minor point: If this is the case, then the expression will be ** re-evaluated for each reference to it. */ sNC.pEList = p->pEList; if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort; if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort; /* Resolve names in table-valued-function arguments */ for(i=0; i<p->pSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; if( pItem->fg.isTabFunc && sqlite3ResolveExprListNames(&sNC, pItem->u1.pFuncArg) ){ return WRC_Abort; } } /* The ORDER BY and GROUP BY clauses may not refer to terms in ** outer queries */ sNC.pNext = 0; sNC.ncFlags |= NC_AllowAgg; |
︙ | ︙ | |||
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 | if( pNC->ncFlags & NC_HasAgg ){ ExprSetProperty(pExpr, EP_Agg); } pNC->ncFlags |= savedHasAgg; return ExprHasProperty(pExpr, EP_Error); } /* ** Resolve all names in all expressions of a SELECT and in all ** decendents of the SELECT, including compounds off of p->pPrior, ** subqueries in expressions, and subqueries used as FROM clause ** terms. ** | > > > > > > > > > > > > > > > > | 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 | if( pNC->ncFlags & NC_HasAgg ){ ExprSetProperty(pExpr, EP_Agg); } pNC->ncFlags |= savedHasAgg; return ExprHasProperty(pExpr, EP_Error); } /* ** Resolve all names for all expression in an expression list. This is ** just like sqlite3ResolveExprNames() except that it works for an expression ** list rather than a single expression. */ int sqlite3ResolveExprListNames( NameContext *pNC, /* Namespace to resolve expressions in. */ ExprList *pList /* The expression list to be analyzed. */ ){ int i; assert( pList!=0 ); for(i=0; i<pList->nExpr; i++){ if( sqlite3ResolveExprNames(pNC, pList->a[i].pExpr) ) return WRC_Abort; } return WRC_Continue; } /* ** Resolve all names in all expressions of a SELECT and in all ** decendents of the SELECT, including compounds off of p->pPrior, ** subqueries in expressions, and subqueries used as FROM clause ** terms. ** |
︙ | ︙ | |||
1485 1486 1487 1488 1489 1490 1491 | Table *pTab, /* The table being referenced */ int type, /* NC_IsCheck or NC_PartIdx */ Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NUL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ | < | < < < | < < < | 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 | Table *pTab, /* The table being referenced */ int type, /* NC_IsCheck or NC_PartIdx */ Expr *pExpr, /* Expression to resolve. May be NULL. */ ExprList *pList /* Expression list to resolve. May be NUL. */ ){ SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ NameContext sNC; /* Name context for pParse->pNewTable */ assert( type==NC_IsCheck || type==NC_PartIdx ); memset(&sNC, 0, sizeof(sNC)); memset(&sSrc, 0, sizeof(sSrc)); sSrc.nSrc = 1; sSrc.a[0].zName = pTab->zName; sSrc.a[0].pTab = pTab; sSrc.a[0].iCursor = -1; sNC.pParse = pParse; sNC.pSrcList = &sSrc; sNC.ncFlags = type; if( sqlite3ResolveExprNames(&sNC, pExpr) ) return; if( pList ) sqlite3ResolveExprListNames(&sNC, pList); } |
Changes to src/select.c.
︙ | ︙ | |||
402 403 404 405 406 407 408 | pRight = &pLeft[1]; for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ Table *pLeftTab = pLeft->pTab; Table *pRightTab = pRight->pTab; int isOuter; if( NEVER(pLeftTab==0 || pRightTab==0) ) continue; | | | | 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | pRight = &pLeft[1]; for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ Table *pLeftTab = pLeft->pTab; Table *pRightTab = pRight->pTab; int isOuter; if( NEVER(pLeftTab==0 || pRightTab==0) ) continue; isOuter = (pRight->fg.jointype & JT_OUTER)!=0; /* When the NATURAL keyword is present, add WHERE clause terms for ** every column that the two tables have in common. */ if( pRight->fg.jointype & JT_NATURAL ){ if( pRight->pOn || pRight->pUsing ){ sqlite3ErrorMsg(pParse, "a NATURAL join may not have " "an ON or USING clause", 0); return 1; } for(j=0; j<pRightTab->nCol; j++){ char *zName; /* Name of column in the right table */ |
︙ | ︙ | |||
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 | ** through regData+nData-1 onto the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ int regData, /* First register holding data to be sorted */ int nData, /* Number of elements in the data array */ int nPrefixReg /* No. of reg prior to regData available for use */ ){ Vdbe *v = pParse->pVdbe; /* Stmt under construction */ int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0); int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ int regBase; /* Regs for sorter record */ int regRecord = ++pParse->nMem; /* Assembled sorter record */ int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ int op; /* Opcode to add sorter record to sorter */ assert( bSeq==0 || bSeq==1 ); if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); regBase = regData - nExpr - bSeq; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } | > > | > | 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 | ** through regData+nData-1 onto the sorter. */ static void pushOntoSorter( Parse *pParse, /* Parser context */ SortCtx *pSort, /* Information about the ORDER BY clause */ Select *pSelect, /* The whole SELECT statement */ int regData, /* First register holding data to be sorted */ int regOrigData, /* First register holding data before packing */ int nData, /* Number of elements in the data array */ int nPrefixReg /* No. of reg prior to regData available for use */ ){ Vdbe *v = pParse->pVdbe; /* Stmt under construction */ int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter)==0); int nExpr = pSort->pOrderBy->nExpr; /* No. of ORDER BY terms */ int nBase = nExpr + bSeq + nData; /* Fields in sorter record */ int regBase; /* Regs for sorter record */ int regRecord = ++pParse->nMem; /* Assembled sorter record */ int nOBSat = pSort->nOBSat; /* ORDER BY terms to skip */ int op; /* Opcode to add sorter record to sorter */ assert( bSeq==0 || bSeq==1 ); assert( nData==1 || regData==regOrigData ); if( nPrefixReg ){ assert( nPrefixReg==nExpr+bSeq ); regBase = regData - nExpr - bSeq; }else{ regBase = pParse->nMem + 1; pParse->nMem += nBase; } sqlite3ExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData, SQLITE_ECEL_DUP|SQLITE_ECEL_REF); if( bSeq ){ sqlite3VdbeAddOp2(v, OP_Sequence, pSort->iECursor, regBase+nExpr); } if( nPrefixReg==0 ){ sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+bSeq, nData); } |
︙ | ︙ | |||
722 723 724 725 726 727 728 | */ u8 ecelFlags; if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){ ecelFlags = SQLITE_ECEL_DUP; }else{ ecelFlags = 0; } | | | 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 | */ u8 ecelFlags; if( eDest==SRT_Mem || eDest==SRT_Output || eDest==SRT_Coroutine ){ ecelFlags = SQLITE_ECEL_DUP; }else{ ecelFlags = 0; } sqlite3ExprCodeExprList(pParse, pEList, regResult, 0, ecelFlags); } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ |
︙ | ︙ | |||
838 839 840 841 842 843 844 | sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1); assert( pSort==0 ); } #endif if( pSort ){ | | | 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 | sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1); assert( pSort==0 ); } #endif if( pSort ){ pushOntoSorter(pParse, pSort, p, r1+nPrefixReg,regResult,1,nPrefixReg); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); } |
︙ | ︙ | |||
864 865 866 867 868 869 870 | pDest->affSdst = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); if( pSort ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ | | | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | pDest->affSdst = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affSdst); if( pSort ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, regResult,1,r1, &pDest->affSdst, 1); sqlite3ExprCacheAffinityChange(pParse, regResult, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); sqlite3ReleaseTempReg(pParse, r1); } |
︙ | ︙ | |||
890 891 892 893 894 895 896 | /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nResultCol==1 ); if( pSort ){ | | | > | 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 | /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nResultCol==1 ); if( pSort ){ pushOntoSorter(pParse, pSort, p, regResult, regResult, 1, nPrefixReg); }else{ assert( regResult==iParm ); /* The LIMIT clause will jump out of the loop for us */ } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ case SRT_Coroutine: /* Send data to a co-routine */ case SRT_Output: { /* Return the results */ testcase( eDest==SRT_Coroutine ); testcase( eDest==SRT_Output ); if( pSort ){ pushOntoSorter(pParse, pSort, p, regResult, regResult, nResultCol, nPrefixReg); }else if( eDest==SRT_Coroutine ){ sqlite3VdbeAddOp1(v, OP_Yield, pDest->iSDParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, nResultCol); sqlite3ExprCacheAffinityChange(pParse, regResult, nResultCol); } break; |
︙ | ︙ | |||
1583 1584 1585 1586 1587 1588 1589 | ** ** Only the column names are computed. Column.zType, Column.zColl, ** and other fields of Column are zeroed. ** ** Return SQLITE_OK on success. If a memory allocation error occurs, ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. */ | | | 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 | ** ** Only the column names are computed. Column.zType, Column.zColl, ** and other fields of Column are zeroed. ** ** Return SQLITE_OK on success. If a memory allocation error occurs, ** store NULL in *paCol and 0 in *pnCol and return SQLITE_NOMEM. */ int sqlite3ColumnsFromExprList( Parse *pParse, /* Parsing context */ ExprList *pEList, /* Expr list from which to derive column names */ i16 *pnCol, /* Write the number of columns here */ Column **paCol /* Write the new column list here */ ){ sqlite3 *db = pParse->db; /* Database connection */ int i, j; /* Loop counters */ |
︙ | ︙ | |||
1750 1751 1752 1753 1754 1755 1756 | } /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside ** is disabled */ assert( db->lookaside.bEnabled==0 ); pTab->nRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); | | | 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 | } /* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside ** is disabled */ assert( db->lookaside.bEnabled==0 ); pTab->nRef = 1; pTab->zName = 0; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol, &pTab->aCol); selectAddColumnTypeAndCollation(pParse, pTab, pSelect); pTab->iPKey = -1; if( db->mallocFailed ){ sqlite3DeleteTable(db, pTab); return 0; } return pTab; |
︙ | ︙ | |||
1929 1930 1931 1932 1933 1934 1935 | ** ** <recursive-table> AS (<setup-query> UNION [ALL] <recursive-query>) ** \___________/ \_______________/ ** p->pPrior p ** ** ** There is exactly one reference to the recursive-table in the FROM clause | | | 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 | ** ** <recursive-table> AS (<setup-query> UNION [ALL] <recursive-query>) ** \___________/ \_______________/ ** p->pPrior p ** ** ** There is exactly one reference to the recursive-table in the FROM clause ** of recursive-query, marked with the SrcList->a[].fg.isRecursive flag. ** ** The setup-query runs once to generate an initial set of rows that go ** into a Queue table. Rows are extracted from the Queue table one by ** one. Each row extracted from Queue is output to pDest. Then the single ** extracted row (now in the iCurrent table) becomes the content of the ** recursive-table for a recursive-query run. The output of the recursive-query ** is added back into the Queue table. Then another row is extracted from Queue |
︙ | ︙ | |||
1994 1995 1996 1997 1998 1999 2000 | regOffset = p->iOffset; p->pLimit = p->pOffset = 0; p->iLimit = p->iOffset = 0; pOrderBy = p->pOrderBy; /* Locate the cursor number of the Current table */ for(i=0; ALWAYS(i<pSrc->nSrc); i++){ | | | 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 | regOffset = p->iOffset; p->pLimit = p->pOffset = 0; p->iLimit = p->iOffset = 0; pOrderBy = p->pOrderBy; /* Locate the cursor number of the Current table */ for(i=0; ALWAYS(i<pSrc->nSrc); i++){ if( pSrc->a[i].fg.isRecursive ){ iCurrent = pSrc->a[i].iCursor; break; } } /* Allocate cursors numbers for Queue and Distinct. The cursor number for ** the Distinct table must be exactly one greater than Queue in order |
︙ | ︙ | |||
3409 3410 3411 3412 3413 3414 3415 | ** effectively converts the OUTER JOIN into an INNER JOIN. ** ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE: ** Ticket #3300 shows that flattening the right term of a LEFT JOIN ** is fraught with danger. Best to avoid the whole thing. If the ** subquery is the right term of a LEFT JOIN, then do not flatten. */ | | | 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 | ** effectively converts the OUTER JOIN into an INNER JOIN. ** ** THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE: ** Ticket #3300 shows that flattening the right term of a LEFT JOIN ** is fraught with danger. Best to avoid the whole thing. If the ** subquery is the right term of a LEFT JOIN, then do not flatten. */ if( (pSubitem->fg.jointype & JT_OUTER)!=0 ){ return 0; } /* Restriction 17: If the sub-query is a compound SELECT, then it must ** use only the UNION ALL operator. And none of the simple select queries ** that make up the compound SELECT are allowed to be aggregate or distinct ** queries. |
︙ | ︙ | |||
3580 3581 3582 3583 3584 3585 3586 | u8 jointype = 0; pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ pSrc = pParent->pSrc; /* FROM clause of the outer query */ if( pSrc ){ assert( pParent==p ); /* First time through the loop */ | | | 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 | u8 jointype = 0; pSubSrc = pSub->pSrc; /* FROM clause of subquery */ nSubSrc = pSubSrc->nSrc; /* Number of terms in subquery FROM clause */ pSrc = pParent->pSrc; /* FROM clause of the outer query */ if( pSrc ){ assert( pParent==p ); /* First time through the loop */ jointype = pSubitem->fg.jointype; }else{ assert( pParent!=p ); /* 2nd and subsequent times through the loop */ pSrc = pParent->pSrc = sqlite3SrcListAppend(db, 0, 0, 0); if( pSrc==0 ){ assert( db->mallocFailed ); break; } |
︙ | ︙ | |||
3620 3621 3622 3623 3624 3625 3626 | ** outer query. */ for(i=0; i<nSubSrc; i++){ sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing); pSrc->a[i+iFrom] = pSubSrc->a[i]; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } | | | 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 | ** outer query. */ for(i=0; i<nSubSrc; i++){ sqlite3IdListDelete(db, pSrc->a[i+iFrom].pUsing); pSrc->a[i+iFrom] = pSubSrc->a[i]; memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); } pSrc->a[iFrom].fg.jointype = jointype; /* Now begin substituting subquery result set expressions for ** references to the iParent in the outer query. ** ** Example: ** ** SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b; |
︙ | ︙ | |||
3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 | ** ** (3) The inner query has a LIMIT clause (since the changes to the WHERE ** close would change the meaning of the LIMIT). ** ** (4) The inner query is the right operand of a LEFT JOIN. (The caller ** enforces this restriction since this routine does not have enough ** information to know.) ** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ static int pushDownWhereTerms( sqlite3 *db, /* The database connection (for malloc()) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ | > > > | 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 | ** ** (3) The inner query has a LIMIT clause (since the changes to the WHERE ** close would change the meaning of the LIMIT). ** ** (4) The inner query is the right operand of a LEFT JOIN. (The caller ** enforces this restriction since this routine does not have enough ** information to know.) ** ** (5) The WHERE clause expression originates in the ON or USING clause ** of a LEFT JOIN. ** ** Return 0 if no changes are made and non-zero if one or more WHERE clause ** terms are duplicated into the subquery. */ static int pushDownWhereTerms( sqlite3 *db, /* The database connection (for malloc()) */ Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ |
︙ | ︙ | |||
3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 | if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor); pWhere = pWhere->pLeft; } if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; while( pSubq ){ pNew = sqlite3ExprDup(db, pWhere, 0); pNew = substExpr(db, pNew, iCursor, pSubq->pEList); pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew); pSubq = pSubq->pPrior; | > | 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 | if( pSubq->pLimit!=0 ){ return 0; /* restriction (3) */ } while( pWhere->op==TK_AND ){ nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor); pWhere = pWhere->pLeft; } if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction 5 */ if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ nChng++; while( pSubq ){ pNew = sqlite3ExprDup(db, pWhere, 0); pNew = substExpr(db, pNew, iCursor, pSubq->pEList); pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew); pSubq = pSubq->pPrior; |
︙ | ︙ | |||
3871 3872 3873 3874 3875 3876 3877 | ** If the source-list item passed as an argument was augmented with an ** INDEXED BY clause, then try to locate the specified index. If there ** was such a clause and the named index cannot be found, return ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate ** pFrom->pIndex and return SQLITE_OK. */ int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){ | | | | | 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 | ** If the source-list item passed as an argument was augmented with an ** INDEXED BY clause, then try to locate the specified index. If there ** was such a clause and the named index cannot be found, return ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate ** pFrom->pIndex and return SQLITE_OK. */ int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){ if( pFrom->pTab && pFrom->fg.isIndexedBy ){ Table *pTab = pFrom->pTab; char *zIndexedBy = pFrom->u1.zIndexedBy; Index *pIdx; for(pIdx=pTab->pIndex; pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); pIdx=pIdx->pNext ); if( !pIdx ){ sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); pParse->checkSchema = 1; return SQLITE_ERROR; } pFrom->pIBIndex = pIdx; } return SQLITE_OK; } /* ** Detect compound SELECT statements that use an ORDER BY clause with ** an alternative collating sequence. ** |
︙ | ︙ | |||
4045 4046 4047 4048 4049 4050 4051 | Table *pTab; ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ | | | | | | 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 | Table *pTab; ExprList *pEList; Select *pSel; Select *pLeft; /* Left-most SELECT statement */ int bMayRecursive; /* True if compound joined by UNION [ALL] */ With *pSavedWith; /* Initial value of pParse->pWith */ /* If pCte->zCteErr is non-NULL at this point, then this is an illegal ** recursive reference to CTE pCte. Leave an error in pParse and return ** early. If pCte->zCteErr is NULL, then this is not a recursive reference. ** In this case, proceed. */ if( pCte->zCteErr ){ sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName); return SQLITE_ERROR; } assert( pFrom->pTab==0 ); pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nRef = 1; |
︙ | ︙ | |||
4079 4080 4081 4082 4083 4084 4085 | for(i=0; i<pSrc->nSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->zDatabase==0 && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ pItem->pTab = pTab; | | | | | | | | 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 | for(i=0; i<pSrc->nSrc; i++){ struct SrcList_item *pItem = &pSrc->a[i]; if( pItem->zDatabase==0 && pItem->zName!=0 && 0==sqlite3StrICmp(pItem->zName, pCte->zName) ){ pItem->pTab = pTab; pItem->fg.isRecursive = 1; pTab->nRef++; pSel->selFlags |= SF_Recursive; } } } /* Only one recursive reference is permitted. */ if( pTab->nRef>2 ){ sqlite3ErrorMsg( pParse, "multiple references to recursive table: %s", pCte->zName ); return SQLITE_ERROR; } assert( pTab->nRef==1 || ((pSel->selFlags&SF_Recursive) && pTab->nRef==2 )); pCte->zCteErr = "circular reference: %s"; pSavedWith = pParse->pWith; pParse->pWith = pWith; sqlite3WalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel); for(pLeft=pSel; pLeft->pPrior; pLeft=pLeft->pPrior); pEList = pLeft->pEList; if( pCte->pCols ){ if( pEList && pEList->nExpr!=pCte->pCols->nExpr ){ sqlite3ErrorMsg(pParse, "table %s has %d values for %d columns", pCte->zName, pEList->nExpr, pCte->pCols->nExpr ); pParse->pWith = pSavedWith; return SQLITE_ERROR; } pEList = pCte->pCols; } sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol, &pTab->aCol); if( bMayRecursive ){ if( pSel->selFlags & SF_Recursive ){ pCte->zCteErr = "multiple recursive references: %s"; }else{ pCte->zCteErr = "recursive reference in a subquery: %s"; } sqlite3WalkSelect(pWalker, pSel); } pCte->zCteErr = 0; pParse->pWith = pSavedWith; } return SQLITE_OK; } #endif |
︙ | ︙ | |||
4209 4210 4211 4212 4213 4214 4215 | /* Look up every table named in the FROM clause of the select. If ** an entry of the FROM clause is a subquery instead of a table or view, ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab; | | | | 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 | /* Look up every table named in the FROM clause of the select. If ** an entry of the FROM clause is a subquery instead of a table or view, ** then create a transient table structure to describe the subquery. */ for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ Table *pTab; assert( pFrom->fg.isRecursive==0 || pFrom->pTab ); if( pFrom->fg.isRecursive ) continue; if( pFrom->pTab!=0 ){ /* This statement has already been prepared. There is no need ** to go further. */ assert( i==0 ); #ifndef SQLITE_OMIT_CTE selectPopWith(pWalker, p); #endif |
︙ | ︙ | |||
4236 4237 4238 4239 4240 4241 4242 | assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nRef = 1; pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); while( pSel->pPrior ){ pSel = pSel->pPrior; } | | | 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 | assert( pFrom->pTab==0 ); if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; pFrom->pTab = pTab = sqlite3DbMallocZero(db, sizeof(Table)); if( pTab==0 ) return WRC_Abort; pTab->nRef = 1; pTab->zName = sqlite3MPrintf(db, "sqlite_sq_%p", (void*)pTab); while( pSel->pPrior ){ pSel = pSel->pPrior; } sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol); pTab->iPKey = -1; pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); pTab->tabFlags |= TF_Ephemeral; #endif }else{ /* An ordinary table or view name in the FROM clause */ assert( pFrom->pTab==0 ); |
︙ | ︙ | |||
4373 4374 4375 4376 4377 4378 4379 | if( IsHiddenColumn(&pTab->aCol[j]) ){ assert(IsVirtual(pTab)); continue; } tableSeen = 1; if( i>0 && zTName==0 ){ | | | 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 | if( IsHiddenColumn(&pTab->aCol[j]) ){ assert(IsVirtual(pTab)); continue; } tableSeen = 1; if( i>0 && zTName==0 ){ if( (pFrom->fg.jointype & JT_NATURAL)!=0 && tableAndColumnIndex(pTabList, i, zName, 0, 0) ){ /* In a NATURAL join, omit the join columns from the ** table to the right of the join */ continue; } if( sqlite3IdListIndex(pFrom->pUsing, zName)>=0 ){ |
︙ | ︙ | |||
4659 4660 4661 4662 4663 4664 4665 | int addrNext = 0; int regAgg; ExprList *pList = pF->pExpr->x.pList; assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); | | | 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 | int addrNext = 0; int regAgg; ExprList *pList = pF->pExpr->x.pList; assert( !ExprHasProperty(pF->pExpr, EP_xIsSelect) ); if( pList ){ nArg = pList->nExpr; regAgg = sqlite3GetTempRange(pParse, nArg); sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP); }else{ nArg = 0; regAgg = 0; } if( pF->iDistinct>=0 ){ addrNext = sqlite3VdbeMakeLabel(v); testcase( nArg==0 ); /* Error condition */ |
︙ | ︙ | |||
4900 4901 4902 4903 4904 4905 4906 | /* Sometimes the code for a subquery will be generated more than ** once, if the subquery is part of the WHERE clause in a LEFT JOIN, ** for example. In that case, do not regenerate the code to manifest ** a view or the co-routine to implement a view. The first instance ** is sufficient, though the subroutine to manifest the view does need ** to be invoked again. */ if( pItem->addrFillSub ){ | | | | 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 | /* Sometimes the code for a subquery will be generated more than ** once, if the subquery is part of the WHERE clause in a LEFT JOIN, ** for example. In that case, do not regenerate the code to manifest ** a view or the co-routine to implement a view. The first instance ** is sufficient, though the subroutine to manifest the view does need ** to be invoked again. */ if( pItem->addrFillSub ){ if( pItem->fg.viaCoroutine==0 ){ sqlite3VdbeAddOp2(v, OP_Gosub, pItem->regReturn, pItem->addrFillSub); } continue; } /* Increment Parse.nHeight by the height of the largest expression ** tree referred to by this, the parent select. The child select ** may contain expression trees of at most ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit ** more conservative than necessary, but much easier than enforcing ** an exact limit. */ pParse->nHeight += sqlite3SelectExprHeight(p); /* Make copies of constant WHERE-clause terms in the outer query down ** inside the subquery. This can help the subquery to run more efficiently. */ if( (pItem->fg.jointype & JT_OUTER)==0 && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor) ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); sqlite3TreeViewSelect(0, p, 0); } |
︙ | ︙ | |||
4947 4948 4949 4950 4951 4952 4953 | sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); | | | | 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 | sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); }else{ /* Generate a subroutine that will fill an ephemeral table with ** the content of this subquery. pItem->addrFillSub will point ** to the address of the generated subroutine. pItem->regReturn ** is a register allocated to hold the subroutine return address */ int topAddr; int onceAddr = 0; int retAddr; assert( pItem->addrFillSub==0 ); pItem->regReturn = ++pParse->nMem; topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); pItem->addrFillSub = topAddr+1; if( pItem->fg.isCorrelated==0 ){ /* If the subquery is not correlated and if we are not inside of ** a trigger, then we only need to compute the value of the subquery ** once. */ onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); }else{ VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); |
︙ | ︙ | |||
5279 5280 5281 5282 5283 5284 5285 | if( sAggInfo.aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCacheClear(pParse); | | | 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 | if( sAggInfo.aCol[i].iSorterColumn>=j ){ nCol++; j++; } } regBase = sqlite3GetTempRange(pParse, nCol); sqlite3ExprCacheClear(pParse); sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0, 0); j = nGroupBy; for(i=0; i<sAggInfo.nColumn; i++){ struct AggInfo_col *pCol = &sAggInfo.aCol[i]; if( pCol->iSorterColumn>=j ){ int r1 = j + regBase; int r2; |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
473 474 475 476 477 478 479 480 481 482 483 484 485 486 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) | > | 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25<<8)) #define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26<<8)) #define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) #define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8)) |
︙ | ︙ |
Changes to src/sqlite3ext.h.
︙ | ︙ | |||
408 409 410 411 412 413 414 415 416 417 418 419 420 421 | #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type #define sqlite3_value_text sqlite3_api->value_text #define sqlite3_value_text16 sqlite3_api->value_text16 #define sqlite3_value_text16be sqlite3_api->value_text16be #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_clear_bindings sqlite3_api->clear_bindings #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob #define sqlite3_blob_bytes sqlite3_api->blob_bytes #define sqlite3_blob_close sqlite3_api->blob_close | > | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type #define sqlite3_value_text sqlite3_api->value_text #define sqlite3_value_text16 sqlite3_api->value_text16 #define sqlite3_value_text16be sqlite3_api->value_text16be #define sqlite3_value_text16le sqlite3_api->value_text16le #define sqlite3_value_type sqlite3_api->value_type #define sqlite3_vmprintf sqlite3_api->vmprintf #define sqlite3_vsnprintf sqlite3_api->vsnprintf #define sqlite3_overload_function sqlite3_api->overload_function #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 #define sqlite3_clear_bindings sqlite3_api->clear_bindings #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob #define sqlite3_blob_bytes sqlite3_api->blob_bytes #define sqlite3_blob_close sqlite3_api->blob_close |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 | ** hash table. */ struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ }; /* ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { | > | 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 | ** hash table. */ struct Module { const sqlite3_module *pModule; /* Callback pointers */ const char *zName; /* Name passed to create_module() */ void *pAux; /* pAux passed to create_module() */ void (*xDestroy)(void *); /* Module destructor function */ Table *pEpoTab; /* Eponymous table for this module */ }; /* ** information about each column of an SQL table is held in an instance ** of this structure. */ struct Column { |
︙ | ︙ | |||
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 | }; /* ** A sort order can be either ASC or DESC. */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ /* ** Column affinity types. ** ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve ** the speed a little by numbering the values consecutively. | > | 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 | }; /* ** A sort order can be either ASC or DESC. */ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ #define SQLITE_SO_UNDEFINED -1 /* No sort order specified */ /* ** Column affinity types. ** ** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and ** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve ** the speed a little by numbering the values consecutively. |
︙ | ︙ | |||
1626 1627 1628 1629 1630 1631 1632 | struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ | < < > | | 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 | struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ ExprList *pCheck; /* All CHECK constraints */ /* ... also used as column name list in a VIEW */ int tnum; /* Root BTree page for this table */ i16 iPKey; /* If not negative, use aCol[iPKey] as the rowid */ i16 nCol; /* Number of columns in this table */ u16 nRef; /* Number of pointers to this Table */ LogEst nRowLogEst; /* Estimated rows in table - from sqlite_stat1 table */ LogEst szTabRow; /* Estimated size of each table row in bytes */ #ifdef SQLITE_ENABLE_COSTMULT LogEst costMult; /* Cost multiplier for using this table */ #endif u8 tabFlags; /* Mask of TF_* values */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE stmt to add a new column */ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE int nModuleArg; /* Number of arguments to the module */ char **azModuleArg; /* 0: module 1: schema 2: vtab name 3...: args */ VTable *pVTable; /* List of VTable objects. */ #endif Trigger *pTrigger; /* List of triggers stored in pSchema */ Schema *pSchema; /* Schema that contains this table */ Table *pNextZombie; /* Next on the Parse.pZombieTab list */ }; |
︙ | ︙ | |||
2280 2281 2282 2283 2284 2285 2286 | char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ | > | | > > | | | > > | > > | | 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 | char *zName; /* Name of the table */ char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ Table *pTab; /* An SQL table corresponding to zName */ Select *pSelect; /* A SELECT statement used in place of a table name */ int addrFillSub; /* Address of subroutine to manifest a subquery */ int regReturn; /* Register holding return address of addrFillSub */ int regResult; /* Registers holding results of a co-routine */ struct { u8 jointype; /* Type of join between this able and the previous */ unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ } fg; #ifndef SQLITE_OMIT_EXPLAIN u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ #endif int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ union { char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ } u1; Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ } a[1]; /* One entry for each identifier on the list */ }; /* ** Permitted values of the SrcList.a.jointype field */ #define JT_INNER 0x0001 /* Any kind of inner or cross join */ |
︙ | ︙ | |||
3018 3019 3020 3021 3022 3023 3024 | struct With { int nCte; /* Number of CTEs in the WITH clause */ With *pOuter; /* Containing WITH clause, or NULL */ struct Cte { /* For each CTE in the WITH clause.... */ char *zName; /* Name of this CTE */ ExprList *pCols; /* List of explicit column names, or NULL */ Select *pSelect; /* The definition of this CTE */ | | | 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 | struct With { int nCte; /* Number of CTEs in the WITH clause */ With *pOuter; /* Containing WITH clause, or NULL */ struct Cte { /* For each CTE in the WITH clause.... */ char *zName; /* Name of this CTE */ ExprList *pCols; /* List of explicit column names, or NULL */ Select *pSelect; /* The definition of this CTE */ const char *zCteErr; /* Error message for circular references */ } a[1]; }; #ifdef SQLITE_DEBUG /* ** An instance of the TreeView object is used for printing the content of ** data structures on sqlite3DebugPrintf() using a tree-like view. |
︙ | ︙ | |||
3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 | void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*); Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); void sqlite3ExprAssignVarNumber(Parse*, Expr*); void sqlite3ExprDelete(sqlite3*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); void sqlite3ExprListDelete(sqlite3*, ExprList*); u32 sqlite3ExprListFlags(const ExprList*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3BeginParse(Parse*,int); void sqlite3CommitInternalChanges(sqlite3*); Table *sqlite3ResultSetOfSelect(Parse*,Select*); void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); | > > > | 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 | void sqlite3ExprAttachSubtrees(sqlite3*,Expr*,Expr*,Expr*); Expr *sqlite3PExpr(Parse*, int, Expr*, Expr*, const Token*); Expr *sqlite3ExprAnd(sqlite3*,Expr*, Expr*); Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*); void sqlite3ExprAssignVarNumber(Parse*, Expr*); void sqlite3ExprDelete(sqlite3*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); void sqlite3ExprListSetSortOrder(ExprList*,int); void sqlite3ExprListSetName(Parse*,ExprList*,Token*,int); void sqlite3ExprListSetSpan(Parse*,ExprList*,ExprSpan*); void sqlite3ExprListDelete(sqlite3*, ExprList*); u32 sqlite3ExprListFlags(const ExprList*); int sqlite3Init(sqlite3*, char**); int sqlite3InitCallback(void*, int, char**, char**); void sqlite3Pragma(Parse*,Token*,Token*,Token*,int); void sqlite3ResetAllSchemasOfConnection(sqlite3*); void sqlite3ResetOneSchema(sqlite3*,int); void sqlite3CollapseDatabaseArray(sqlite3*); void sqlite3BeginParse(Parse*,int); void sqlite3CommitInternalChanges(sqlite3*); void sqlite3DeleteColumnNames(sqlite3*,Table*); int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**); Table *sqlite3ResultSetOfSelect(Parse*,Select*); void sqlite3OpenMasterTable(Parse *, int); Index *sqlite3PrimaryKeyIndex(Table*); i16 sqlite3ColumnOfIndex(Index*, i16); void sqlite3StartTable(Parse*,Token*,Token*,int,int,int,int); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); |
︙ | ︙ | |||
3285 3286 3287 3288 3289 3290 3291 | RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); void sqlite3RowSetClear(RowSet*); void sqlite3RowSetInsert(RowSet*, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); | | | 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 | RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); void sqlite3RowSetClear(RowSet*); void sqlite3RowSetInsert(RowSet*, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); void sqlite3CreateView(Parse*,Token*,Token*,Token*,ExprList*,Select*,int,int); #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) int sqlite3ViewGetColumnNames(Parse*,Table*); #else # define sqlite3ViewGetColumnNames(A,B) 0 #endif |
︙ | ︙ | |||
3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 | IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, | > | 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 | IdList *sqlite3IdListAppend(sqlite3*, IdList*, Token*); int sqlite3IdListIndex(IdList*,const char*); SrcList *sqlite3SrcListEnlarge(sqlite3*, SrcList*, int, int); SrcList *sqlite3SrcListAppend(sqlite3*, SrcList*, Token*, Token*); SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, Token*, Select*, Expr*, IdList*); void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); int sqlite3IndexedByLookup(Parse *, struct SrcList_item *); void sqlite3SrcListShiftJoinType(SrcList*); void sqlite3SrcListAssignCursors(Parse*, SrcList*); void sqlite3IdListDelete(sqlite3*, IdList*); void sqlite3SrcListDelete(sqlite3*, SrcList*); Index *sqlite3AllocateIndexObject(sqlite3*,i16,int,char**); Index *sqlite3CreateIndex(Parse*,Token*,Token*,SrcList*,ExprList*,int,Token*, |
︙ | ︙ | |||
3360 3361 3362 3363 3364 3365 3366 | void sqlite3ExprCacheAffinityChange(Parse*, int, int); void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); void sqlite3ExprCodeAndCache(Parse*, Expr*, int); | | > | 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 | void sqlite3ExprCacheAffinityChange(Parse*, int, int); void sqlite3ExprCode(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); void sqlite3ExprCodeAndCache(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ #define SQLITE_ECEL_REF 0x04 /* Use ExprList.u.x.iOrderByCol */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); |
︙ | ︙ | |||
3534 3535 3536 3537 3538 3539 3540 | #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint | | | 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 | #define putVarint32(A,B) \ (u8)(((u32)(B)<(u32)0x80)?(*(A)=(unsigned char)(B)),1:\ sqlite3PutVarint((A),(B))) #define getVarint sqlite3GetVarint #define putVarint sqlite3PutVarint const char *sqlite3IndexAffinityStr(sqlite3*, Index*); void sqlite3TableAffinity(Vdbe*, Table*, int); char sqlite3CompareAffinity(Expr *pExpr, char aff2); int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); |
︙ | ︙ | |||
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 | void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); int sqlite3CodeSubselect(Parse *, Expr *, int, int); void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); int sqlite3ResolveExprNames(NameContext*, Expr*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); | > | 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 | void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*); int sqlite3CodeSubselect(Parse *, Expr *, int, int); void sqlite3SelectPrep(Parse*, Select*, NameContext*); void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p); int sqlite3MatchSpanName(const char*, const char*, const char*, const char*); int sqlite3ResolveExprNames(NameContext*, Expr*); int sqlite3ResolveExprListNames(NameContext*, ExprList*); void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*); void sqlite3ResolveSelfReference(Parse*,Table*,int,Expr*,ExprList*); int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*); void sqlite3ColumnDefault(Vdbe *, Table *, int, int); void sqlite3AlterFinishAddColumn(Parse *, Token *); void sqlite3AlterBeginAddColumn(Parse *, SrcList *); CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*); |
︙ | ︙ | |||
3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 | void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); int sqlite3VtabSavepoint(sqlite3 *, int, int); void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); VTable *sqlite3GetVTable(sqlite3*, Table*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); int sqlite3VtabCallConnect(Parse*, Table*); | > > | 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 | void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); int sqlite3VtabSavepoint(sqlite3 *, int, int); void sqlite3VtabImportErrmsg(Vdbe*, sqlite3_vtab*); VTable *sqlite3GetVTable(sqlite3*, Table*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif int sqlite3VtabEponymousTableInit(Parse*,Module*); void sqlite3VtabEponymousTableClear(sqlite3*,Module*); void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*, int); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); int sqlite3VtabCallCreate(sqlite3*, int, const char *, char **); int sqlite3VtabCallConnect(Parse*, Table*); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 | ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fts5_init(sqlite3*,char**,const sqlite3_api_routines*); static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, { "eval", sqlite3_eval_init }, #ifdef SQLITE_ENABLE_FTS5 { "fts5", sqlite3_fts5_init }, #endif { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, { "spellfix", sqlite3_spellfix_init }, { "totype", sqlite3_totype_init }, { "wholenumber", sqlite3_wholenumber_init }, }; sqlite3 *db; const char *zName; int i, j, rc; | > > > > | 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 | ){ extern int sqlite3_amatch_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_closure_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_eval_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fileio_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fuzzer_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_ieee_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_json_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_nextchar_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_percentile_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_spellfix_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_totype_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_wholenumber_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_fts5_init(sqlite3*,char**,const sqlite3_api_routines*); static const struct { const char *zExtName; int (*pInit)(sqlite3*,char**,const sqlite3_api_routines*); } aExtension[] = { { "amatch", sqlite3_amatch_init }, { "closure", sqlite3_closure_init }, { "eval", sqlite3_eval_init }, #ifdef SQLITE_ENABLE_FTS5 { "fts5", sqlite3_fts5_init }, #endif { "fileio", sqlite3_fileio_init }, { "fuzzer", sqlite3_fuzzer_init }, { "ieee754", sqlite3_ieee_init }, { "json", sqlite3_json_init }, { "nextchar", sqlite3_nextchar_init }, { "percentile", sqlite3_percentile_init }, { "regexp", sqlite3_regexp_init }, { "series", sqlite3_series_init }, { "spellfix", sqlite3_spellfix_init }, { "totype", sqlite3_totype_init }, { "wholenumber", sqlite3_wholenumber_init }, }; sqlite3 *db; const char *zName; int i, j, rc; |
︙ | ︙ |
Changes to src/treeview.c.
︙ | ︙ | |||
81 82 83 84 85 86 87 88 | /* ** Generate a human-readable description of a the Select object. */ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); | > > | | | | > > > > > | | | | | | | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < < | > > | 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 | /* ** Generate a human-readable description of a the Select object. */ void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ int n = 0; int cnt = 0; pView = sqlite3TreeViewPush(pView, moreToFollow); do{ sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags ); if( cnt++ ) sqlite3TreeViewPop(pView); if( p->pPrior ){ n = 1000; }else{ n = 0; if( p->pSrc && p->pSrc->nSrc ) n++; if( p->pWhere ) n++; if( p->pGroupBy ) n++; if( p->pHaving ) n++; if( p->pOrderBy ) n++; if( p->pLimit ) n++; if( p->pOffset ) n++; } sqlite3TreeViewExprList(pView, p->pEList, (n--)>0, "result-set"); if( p->pSrc && p->pSrc->nSrc ){ int i; pView = sqlite3TreeViewPush(pView, (n--)>0); sqlite3TreeViewLine(pView, "FROM"); for(i=0; i<p->pSrc->nSrc; i++){ struct SrcList_item *pItem = &p->pSrc->a[i]; StrAccum x; char zLine[100]; sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); sqlite3XPrintf(&x, 0, "{%d,*}", pItem->iCursor); if( pItem->zDatabase ){ sqlite3XPrintf(&x, 0, " %s.%s", pItem->zDatabase, pItem->zName); }else if( pItem->zName ){ sqlite3XPrintf(&x, 0, " %s", pItem->zName); } if( pItem->pTab ){ sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); } if( pItem->zAlias ){ sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); } if( pItem->fg.jointype & JT_LEFT ){ sqlite3XPrintf(&x, 0, " LEFT-JOIN"); } sqlite3StrAccumFinish(&x); sqlite3TreeViewItem(pView, zLine, i<p->pSrc->nSrc-1); if( pItem->pSelect ){ sqlite3TreeViewSelect(pView, pItem->pSelect, 0); } if( pItem->fg.isTabFunc ){ sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); } sqlite3TreeViewPop(pView); } sqlite3TreeViewPop(pView); } if( p->pWhere ){ sqlite3TreeViewItem(pView, "WHERE", (n--)>0); sqlite3TreeViewExpr(pView, p->pWhere, 0); sqlite3TreeViewPop(pView); } if( p->pGroupBy ){ sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); } if( p->pHaving ){ sqlite3TreeViewItem(pView, "HAVING", (n--)>0); sqlite3TreeViewExpr(pView, p->pHaving, 0); sqlite3TreeViewPop(pView); } if( p->pOrderBy ){ sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); } if( p->pLimit ){ sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); sqlite3TreeViewExpr(pView, p->pLimit, 0); sqlite3TreeViewPop(pView); } if( p->pOffset ){ sqlite3TreeViewItem(pView, "OFFSET", (n--)>0); sqlite3TreeViewExpr(pView, p->pOffset, 0); sqlite3TreeViewPop(pView); } if( p->pPrior ){ const char *zOp = "UNION"; switch( p->op ){ case TK_ALL: zOp = "UNION ALL"; break; case TK_INTERSECT: zOp = "INTERSECT"; break; case TK_EXCEPT: zOp = "EXCEPT"; break; } sqlite3TreeViewItem(pView, zOp, 1); } p = p->pPrior; }while( p!=0 ); sqlite3TreeViewPop(pView); } /* ** Generate a human-readable explanation of an expression tree. */ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ |
︙ | ︙ | |||
418 419 420 421 422 423 424 425 426 427 428 429 430 431 | pView = sqlite3TreeViewPush(pView, moreToFollow); if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; i<pList->nExpr; i++){ sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1); } } sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ | > > > > > > | 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | pView = sqlite3TreeViewPush(pView, moreToFollow); if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; if( pList==0 ){ sqlite3TreeViewLine(pView, "%s (empty)", zLabel); }else{ sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; i<pList->nExpr; i++){ int j = pList->a[i].u.x.iOrderByCol; if( j ){ sqlite3TreeViewPush(pView, 0); sqlite3TreeViewLine(pView, "iOrderByCol=%d", j); } sqlite3TreeViewExpr(pView, pList->a[i].pExpr, i<pList->nExpr-1); if( j ) sqlite3TreeViewPop(pView); } } sqlite3TreeViewPop(pView); } #endif /* SQLITE_DEBUG */ |
Changes to src/update.c.
︙ | ︙ | |||
386 387 388 389 390 391 392 | } if( okOnePass ){ sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, | | | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | } if( okOnePass ){ sqlite3VdbeChangeToNoop(v, addrOpen); nKey = nPk; regKey = iPk; }else{ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, regKey, sqlite3IndexAffinityStr(db, pPk), nPk); sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, regKey); } sqlite3WhereEnd(pWInfo); } /* Initialize the count of updated rows */ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
567 568 569 570 571 572 573 | assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } | | | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | assert( p->magic==VDBE_MAGIC_RUN ); /* sqlite3_step() verifies this */ sqlite3VdbeEnter(p); if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } assert( p->rc==SQLITE_OK || (p->rc&0xff)==SQLITE_BUSY ); assert( p->bIsReader || p->readOnly!=0 ); p->rc = SQLITE_OK; p->iCurrentTime = 0; assert( p->explain==0 ); p->pResultSet = 0; db->busyHandler.nBusy = 0; if( db->u1.isInterrupted ) goto abort_due_to_interrupt; |
︙ | ︙ | |||
3081 3082 3083 3084 3085 3086 3087 | rc = SQLITE_READONLY; goto abort_due_to_error; } pBt = db->aDb[pOp->p1].pBt; if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); | > > | | | 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 | rc = SQLITE_READONLY; goto abort_due_to_error; } pBt = db->aDb[pOp->p1].pBt; if( pBt ){ rc = sqlite3BtreeBeginTrans(pBt, pOp->p2); testcase( rc==SQLITE_BUSY_SNAPSHOT ); testcase( rc==SQLITE_BUSY_RECOVERY ); if( (rc&0xff)==SQLITE_BUSY ){ p->pc = (int)(pOp - aOp); p->rc = rc; goto vdbe_return; } if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( pOp->p2 && p->usesStmtJournal |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
607 608 609 610 611 612 613 | ** returned if this statement was compiled using the legacy ** sqlite3_prepare() interface. According to the docs, this can only ** be one of the values in the first assert() below. Variable p->rc ** contains the value that would be returned if sqlite3_finalize() ** were called on statement p. */ assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR | | | 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 | ** returned if this statement was compiled using the legacy ** sqlite3_prepare() interface. According to the docs, this can only ** be one of the values in the first assert() below. Variable p->rc ** contains the value that would be returned if sqlite3_finalize() ** were called on statement p. */ assert( rc==SQLITE_ROW || rc==SQLITE_DONE || rc==SQLITE_ERROR || (rc&0xff)==SQLITE_BUSY || rc==SQLITE_MISUSE ); assert( (p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE) || p->rc==p->rcApp ); if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ /* If this statement was prepared using sqlite3_prepare_v2(), and an ** error has occurred, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 | CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : "nil"; int n = sqlite3Strlen30(zColl); if( n==6 && memcmp(zColl,"BINARY",6)==0 ){ zColl = "B"; n = 1; } | | > | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 | CollSeq *pColl = pKeyInfo->aColl[j]; const char *zColl = pColl ? pColl->zName : "nil"; int n = sqlite3Strlen30(zColl); if( n==6 && memcmp(zColl,"BINARY",6)==0 ){ zColl = "B"; n = 1; } if( i+n>nTemp-7 ){ memcpy(&zTemp[i],",...",4); i += 4; break; } zTemp[i++] = ','; if( pKeyInfo->aSortOrder[j] ){ zTemp[i++] = '-'; } memcpy(&zTemp[i], zColl, n+1); |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | Module *pDel; char *zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); assert( pDel==0 || pDel==pMod ); if( pDel ){ db->mallocFailed = 1; sqlite3DbFree(db, pDel); } } | > | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | Module *pDel; char *zCopy = (char *)(&pMod[1]); memcpy(zCopy, zName, nName+1); pMod->zName = zCopy; pMod->pModule = pModule; pMod->pAux = pAux; pMod->xDestroy = xDestroy; pMod->pEpoTab = 0; pDel = (Module *)sqlite3HashInsert(&db->aModule,zCopy,(void*)pMod); assert( pDel==0 || pDel==pMod ); if( pDel ){ db->mallocFailed = 1; sqlite3DbFree(db, pDel); } } |
︙ | ︙ | |||
281 282 283 284 285 286 287 | /* ** Add a new module argument to pTable->azModuleArg[]. ** The string is not copied - the pointer is stored. The ** string will be freed automatically when the table is ** deleted. */ static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ | < | < < < < < < > < | > | 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 | /* ** Add a new module argument to pTable->azModuleArg[]. ** The string is not copied - the pointer is stored. The ** string will be freed automatically when the table is ** deleted. */ static void addModuleArgument(sqlite3 *db, Table *pTable, char *zArg){ int nBytes = sizeof(char *)*(2+pTable->nModuleArg); char **azModuleArg; azModuleArg = sqlite3DbRealloc(db, pTable->azModuleArg, nBytes); if( azModuleArg==0 ){ sqlite3DbFree(db, zArg); }else{ int i = pTable->nModuleArg++; azModuleArg[i] = zArg; azModuleArg[i+1] = 0; pTable->azModuleArg = azModuleArg; } } /* ** The parser calls this routine when it first sees a CREATE VIRTUAL TABLE ** statement. The module name has been parsed, but the optional list ** of parameters that follow the module name are still pending. */ |
︙ | ︙ | |||
700 701 702 703 704 705 706 | zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ | | | 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | zMod = pTab->azModuleArg[0]; pMod = (Module*)sqlite3HashFind(&db->aModule, zMod); /* If the module has been registered and includes a Create method, ** invoke it now. If the module has not been registered, return an ** error. Otherwise, do nothing. */ if( pMod==0 || pMod->pModule->xCreate==0 || pMod->pModule->xDestroy==0 ){ *pzErr = sqlite3MPrintf(db, "no such module: %s", zMod); rc = SQLITE_ERROR; }else{ rc = vtabCallConstructor(db, pTab, pMod, pMod->pModule->xCreate, pzErr); } /* Justification of ALWAYS(): The xConstructor method is required to |
︙ | ︙ | |||
802 803 804 805 806 807 808 809 810 811 812 813 814 815 | int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ VTable *p; for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } } p = vtabDisconnectAll(db, pTab); | > | > > | 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 | int sqlite3VtabCallDestroy(sqlite3 *db, int iDb, const char *zTab){ int rc = SQLITE_OK; Table *pTab; pTab = sqlite3FindTable(db, zTab, db->aDb[iDb].zName); if( ALWAYS(pTab!=0 && pTab->pVTable!=0) ){ VTable *p; int (*xDestroy)(sqlite3_vtab *); for(p=pTab->pVTable; p; p=p->pNext){ assert( p->pVtab ); if( p->pVtab->nRef>0 ){ return SQLITE_LOCKED; } } p = vtabDisconnectAll(db, pTab); xDestroy = p->pMod->pModule->xDestroy; assert( xDestroy!=0 ); /* Checked before the virtual table is created */ rc = xDestroy(p->pVtab); /* Remove the sqlite3_vtab* from the aVTrans[] array, if applicable */ if( rc==SQLITE_OK ){ assert( pTab->pVTable==p && p->pNext==0 ); p->pVtab = 0; pTab->pVTable = 0; sqlite3VtabUnlock(p); } |
︙ | ︙ | |||
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 | if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ pToplevel->db->mallocFailed = 1; } } /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. ** ** The results of this routine are undefined unless it is called from ** within an xUpdate method. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | if( apVtabLock ){ pToplevel->apVtabLock = apVtabLock; pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; }else{ pToplevel->db->mallocFailed = 1; } } /* ** Check to see if virtual tale module pMod can be have an eponymous ** virtual table instance. If it can, create one if one does not already ** exist. Return non-zero if the eponymous virtual table instance exists ** when this routine returns, and return zero if it does not exist. ** ** An eponymous virtual table instance is one that is named after its ** module, and more importantly, does not require a CREATE VIRTUAL TABLE ** statement in order to come into existance. Eponymous virtual table ** instances always exist. They cannot be DROP-ed. ** ** Any virtual table module for which xConnect and xCreate are the same ** method can have an eponymous virtual table instance. */ int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){ const sqlite3_module *pModule = pMod->pModule; Table *pTab; char *zErr = 0; int nName; int rc; sqlite3 *db = pParse->db; if( pMod->pEpoTab ) return 1; if( pModule->xCreate!=0 && pModule->xCreate!=pModule->xConnect ) return 0; nName = sqlite3Strlen30(pMod->zName) + 1; pTab = sqlite3DbMallocZero(db, sizeof(Table) + nName); if( pTab==0 ) return 0; pMod->pEpoTab = pTab; pTab->zName = (char*)&pTab[1]; memcpy(pTab->zName, pMod->zName, nName); pTab->nRef = 1; pTab->pSchema = db->aDb[0].pSchema; pTab->tabFlags |= TF_Virtual; pTab->nModuleArg = 0; pTab->iPKey = -1; addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); addModuleArgument(db, pTab, 0); addModuleArgument(db, pTab, sqlite3DbStrDup(db, pTab->zName)); rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr); if( rc ){ sqlite3ErrorMsg(pParse, "%s", zErr); sqlite3DbFree(db, zErr); sqlite3VtabEponymousTableClear(db, pMod); return 0; } return 1; } /* ** Erase the eponymous virtual table instance associated with ** virtual table module pMod, if it exists. */ void sqlite3VtabEponymousTableClear(sqlite3 *db, Module *pMod){ Table *pTab = pMod->pEpoTab; if( (pTab = pMod->pEpoTab)!=0 ){ sqlite3DeleteColumnNames(db, pTab); sqlite3VtabClear(db, pTab); sqlite3DbFree(db, pTab); pMod->pEpoTab = 0; } } /* ** Return the ON CONFLICT resolution mode in effect for the virtual ** table update operation currently in progress. ** ** The results of this routine are undefined unless it is called from ** within an xUpdate method. |
︙ | ︙ |
Changes to src/walker.c.
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 109 110 111 112 113 | struct SrcList_item *pItem; pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } } } return WRC_Continue; } /* | > > > > > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | struct SrcList_item *pItem; pSrc = p->pSrc; if( ALWAYS(pSrc) ){ for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ if( sqlite3WalkSelect(pWalker, pItem->pSelect) ){ return WRC_Abort; } if( pItem->fg.isTabFunc && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg) ){ return WRC_Abort; } } } return WRC_Continue; } /* |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
167 168 169 170 171 172 173 | /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. */ static WhereTerm *whereScanNext(WhereScan *pScan){ int iCur; /* The cursor on the LHS of the term */ | | | | | | | | | | | | | 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 | /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. */ static WhereTerm *whereScanNext(WhereScan *pScan){ int iCur; /* The cursor on the LHS of the term */ i16 iColumn; /* The column on the LHS of the term. -1 for IPK */ Expr *pX; /* An expression being tested */ WhereClause *pWC; /* Shorthand for pScan->pWC */ WhereTerm *pTerm; /* The term being tested */ int k = pScan->k; /* Where to start scanning */ while( pScan->iEquiv<=pScan->nEquiv ){ iCur = pScan->aiCur[pScan->iEquiv-1]; iColumn = pScan->aiColumn[pScan->iEquiv-1]; while( (pWC = pScan->pWC)!=0 ){ for(pTerm=pWC->a+k; k<pWC->nTerm; k++, pTerm++){ if( pTerm->leftCursor==iCur && pTerm->u.leftColumn==iColumn && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) ){ if( (pTerm->eOperator & WO_EQUIV)!=0 && pScan->nEquiv<ArraySize(pScan->aiCur) ){ int j; pX = sqlite3ExprSkipCollate(pTerm->pExpr->pRight); assert( pX->op==TK_COLUMN ); for(j=0; j<pScan->nEquiv; j++){ if( pScan->aiCur[j]==pX->iTable && pScan->aiColumn[j]==pX->iColumn ){ break; } } if( j==pScan->nEquiv ){ pScan->aiCur[j] = pX->iTable; pScan->aiColumn[j] = pX->iColumn; pScan->nEquiv++; } } if( (pTerm->eOperator & pScan->opMask)!=0 ){ /* Verify the affinity and collating sequence match */ if( pScan->zCollName && (pTerm->eOperator & WO_ISNULL)==0 ){ CollSeq *pColl; Parse *pParse = pWC->pWInfo->pParse; |
︙ | ︙ | |||
219 220 221 222 223 224 225 | if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN | | | | | 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 | if( pColl==0 ) pColl = pParse->db->pDfltColl; if( sqlite3StrICmp(pColl->zName, pScan->zCollName) ){ continue; } } if( (pTerm->eOperator & (WO_EQ|WO_IS))!=0 && (pX = pTerm->pExpr->pRight)->op==TK_COLUMN && pX->iTable==pScan->aiCur[0] && pX->iColumn==pScan->aiColumn[0] ){ testcase( pTerm->eOperator & WO_IS ); continue; } pScan->k = k+1; return pTerm; } } } pScan->pWC = pScan->pWC->pOuter; k = 0; } pScan->pWC = pScan->pOrigWC; k = 0; pScan->iEquiv++; } return 0; } /* ** Initialize a WHERE clause scanner object. Return a pointer to the ** first match. Return NULL if there are no matches. |
︙ | ︙ | |||
281 282 283 284 285 286 287 | pScan->zCollName = pIdx->azColl[j]; }else{ pScan->idxaff = 0; pScan->zCollName = 0; } pScan->opMask = opMask; pScan->k = 0; | | | | | | < < | | | | 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 | pScan->zCollName = pIdx->azColl[j]; }else{ pScan->idxaff = 0; pScan->zCollName = 0; } pScan->opMask = opMask; pScan->k = 0; pScan->aiCur[0] = iCur; pScan->aiColumn[0] = iColumn; pScan->nEquiv = 1; pScan->iEquiv = 1; return whereScanNext(pScan); } /* ** Search for a term in the WHERE clause that is of the form "X <op> <expr>" ** where X is a reference to the iColumn of table iCur and <op> is one of ** the WO_xx operator codes specified by the op parameter. ** Return a pointer to the term. Return 0 if not found. ** ** The term returned might by Y=<expr> if there is another constraint in ** the WHERE clause that specifies that X=Y. Any such constraints will be ** identified by the WO_EQUIV bit in the pTerm->eOperator field. The ** aiCur[]/iaColumn[] arrays hold X and all its equivalents. There are 11 ** slots in aiCur[]/aiColumn[] so that means we can look for X plus up to 10 ** other equivalent values. Hence a search for X will return <expr> if X=A1 ** and A1=A2 and A2=A3 and ... and A9=A10 and A10=<expr>. ** ** If there are multiple terms in the WHERE clause of the form "X <op> <expr>" ** then try for the one with no dependencies on <expr> - in other words where ** <expr> is a constant expression of some kind. Only return entries of ** the form "X <op> Y" where Y is a column in another table if no terms of ** the form "X <op> <const-expr>" exist. If no terms with a constant RHS ** exist, try to return a term that does not use WO_EQUIV. |
︙ | ︙ | |||
705 706 707 708 709 710 711 | sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ sqlite3ExprCachePush(pParse); pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; | | | | | 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 | sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "for %s", pTable->zName)); /* Fill the automatic index with content */ sqlite3ExprCachePush(pParse); pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom]; if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); VdbeCoverage(v); VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); }else{ addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); } if( pPartial ){ iContinue = sqlite3VdbeMakeLabel(v); sqlite3ExprIfFalse(pParse, pPartial, iContinue, SQLITE_JUMPIFNULL); pLoop->wsFlags |= WHERE_PARTIALIDX; } regRecord = sqlite3GetTempReg(pParse); sqlite3GenerateIndexKey(pParse, pIdx, pLevel->iTabCur, regRecord, 0, 0, 0, 0); sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); if( pTabItem->fg.viaCoroutine ){ translateColumnToCopy(v, addrTop, pLevel->iTabCur, pTabItem->regResult); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrTop); pTabItem->fg.viaCoroutine = 0; }else{ sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); } sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); sqlite3VdbeJumpHere(v, addrTop); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ExprCachePop(pParse); |
︙ | ︙ | |||
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 | nRet += pTerm->truthProb; }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** This function is called to estimate the number of rows visited by a ** range-scan on a skip-scan index. For example: ** ** CREATE INDEX i1 ON t1(a, b, c); | > > > > > > > > > > > > > > | 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 | nRet += pTerm->truthProb; }else if( (pTerm->wtFlags & TERM_VNULL)==0 ){ nRet -= 20; assert( 20==sqlite3LogEst(4) ); } } return nRet; } #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** Return the affinity for a single column of an index. */ static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; } return pIdx->zColAff[iCol]; } #endif #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 /* ** This function is called to estimate the number of rows visited by a ** range-scan on a skip-scan index. For example: ** ** CREATE INDEX i1 ON t1(a, b, c); |
︙ | ︙ | |||
1173 1174 1175 1176 1177 1178 1179 | Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; sqlite3 *db = pParse->db; int nLower = -1; int nUpper = p->nSample+1; int rc = SQLITE_OK; int iCol = p->aiColumn[nEq]; | | | 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 | Index *p = pLoop->u.btree.pIndex; int nEq = pLoop->u.btree.nEq; sqlite3 *db = pParse->db; int nLower = -1; int nUpper = p->nSample+1; int rc = SQLITE_OK; int iCol = p->aiColumn[nEq]; u8 aff = sqlite3IndexColumnAffinity(db, p, iCol); CollSeq *pColl; sqlite3_value *p1 = 0; /* Value extracted from pLower */ sqlite3_value *p2 = 0; /* Value extracted from pUpper */ sqlite3_value *pVal = 0; /* Value extracted from record */ pColl = sqlite3LocateCollSeq(pParse, p->azColl[nEq]); |
︙ | ︙ | |||
1321 1322 1323 1324 1325 1326 1327 | int iLwrIdx = -2; /* aSample[] for the lower bound */ int iUprIdx = -1; /* aSample[] for the upper bound */ if( pRec ){ testcase( pRec->nField!=pBuilder->nRecValid ); pRec->nField = pBuilder->nRecValid; } | | | < < < | 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 | int iLwrIdx = -2; /* aSample[] for the lower bound */ int iUprIdx = -1; /* aSample[] for the upper bound */ if( pRec ){ testcase( pRec->nField!=pBuilder->nRecValid ); pRec->nField = pBuilder->nRecValid; } aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq); assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER ); /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; iUpper = p->nRowEst0; }else{ /* Note: this call could be optimized away - since the same values must ** have been requested when testing key $P in whereEqualScanEst(). */ |
︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 | /* This is an optimization only. The call to sqlite3Stat4ProbeSetValue() ** below would return the same value. */ if( nEq>=p->nColumn ){ *pnRow = 1; return SQLITE_OK; } | | | 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 | /* This is an optimization only. The call to sqlite3Stat4ProbeSetValue() ** below would return the same value. */ if( nEq>=p->nColumn ){ *pnRow = 1; return SQLITE_OK; } aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1); rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk); pBuilder->pRec = pRec; if( rc!=SQLITE_OK ) return rc; if( bOk==0 ) return SQLITE_NOTFOUND; pBuilder->nRecValid = nEq; whereKeyStats(pParse, p, pRec, 0, a); |
︙ | ︙ | |||
1910 1911 1912 1913 1914 1915 1916 1917 | WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ #if WHERETRACE_ENABLED | > | | | | | | | > | 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 | WhereInfo *pWInfo = pBuilder->pWInfo; sqlite3 *db = pWInfo->pParse->db; /* If pBuilder->pOrSet is defined, then only keep track of the costs ** and prereqs. */ if( pBuilder->pOrSet!=0 ){ if( pTemplate->nLTerm ){ #if WHERETRACE_ENABLED u16 n = pBuilder->pOrSet->n; int x = #endif whereOrInsert(pBuilder->pOrSet, pTemplate->prereq, pTemplate->rRun, pTemplate->nOut); #if WHERETRACE_ENABLED /* 0x8 */ if( sqlite3WhereTrace & 0x8 ){ sqlite3DebugPrintf(x?" or-%d: ":" or-X: ", n); whereLoopPrint(pTemplate, pBuilder->pWC); } #endif } return SQLITE_OK; } /* Look for an existing WhereLoop to replace with pTemplate */ whereLoopAdjustCost(pWInfo->pLoops, pTemplate); ppPrev = whereLoopFindLesser(&pWInfo->pLoops, pTemplate); |
︙ | ︙ | |||
2124 2125 2126 2127 2128 2129 2130 | pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM; assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; | | | 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 | pNew = pBuilder->pNew; if( db->mallocFailed ) return SQLITE_NOMEM; assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); if( pNew->wsFlags & WHERE_BTM_LIMIT ){ opMask = WO_LT|WO_LE; }else if( /*pProbe->tnum<=0 ||*/ (pSrc->fg.jointype & JT_LEFT)!=0 ){ opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE; }else{ opMask = WO_EQ|WO_IN|WO_GT|WO_GE|WO_LT|WO_LE|WO_ISNULL|WO_IS; } if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE); assert( pNew->u.btree.nEq<pProbe->nColumn ); |
︙ | ︙ | |||
2498 2499 2500 2501 2502 2503 2504 | pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; pTab = pSrc->pTab; pWC = pBuilder->pWC; assert( !IsVirtual(pSrc->pTab) ); | | | | | | | | | | | 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 2560 2561 2562 2563 2564 | pWInfo = pBuilder->pWInfo; pTabList = pWInfo->pTabList; pSrc = pTabList->a + pNew->iTab; pTab = pSrc->pTab; pWC = pBuilder->pWC; assert( !IsVirtual(pSrc->pTab) ); if( pSrc->pIBIndex ){ /* An INDEXED BY clause specifies a particular index to use */ pProbe = pSrc->pIBIndex; }else if( !HasRowid(pTab) ){ pProbe = pTab->pIndex; }else{ /* There is no INDEXED BY clause. Create a fake Index object in local ** variable sPk to represent the rowid primary key index. Make this ** fake index the first in a chain of Index objects with all of the real ** indices to follow */ Index *pFirst; /* First of real indices on the table */ memset(&sPk, 0, sizeof(Index)); sPk.nKeyCol = 1; sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; sPk.aiRowLogEst = aiRowEstPk; sPk.onError = OE_Replace; sPk.pTable = pTab; sPk.szIdxRow = pTab->szTabRow; aiRowEstPk[0] = pTab->nRowLogEst; aiRowEstPk[1] = 0; pFirst = pSrc->pTab->pIndex; if( pSrc->fg.notIndexed==0 ){ /* The real indices of the table are only considered if the ** NOT INDEXED qualifier is omitted from the FROM clause */ sPk.pNext = pFirst; } pProbe = &sPk; } rSize = pTab->nRowLogEst; rLogSize = estLog(rSize); #ifndef SQLITE_OMIT_AUTOMATIC_INDEX /* Automatic indexes */ if( !pBuilder->pOrSet /* Not part of an OR optimization */ && (pWInfo->wctrlFlags & WHERE_NO_AUTOINDEX)==0 && (pWInfo->pParse->db->flags & SQLITE_AutoIndex)!=0 && pSrc->pIBIndex==0 /* Has no INDEXED BY clause */ && !pSrc->fg.notIndexed /* Has no NOT INDEXED clause */ && HasRowid(pTab) /* Is not a WITHOUT ROWID table. (FIXME: Why not?) */ && !pSrc->fg.isCorrelated /* Not a correlated subquery */ && !pSrc->fg.isRecursive /* Not a recursive common table expression. */ ){ /* Generate auto-index WhereLoops */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTerm<pWCEnd; pTerm++){ if( pTerm->prereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ |
︙ | ︙ | |||
2660 2661 2662 2663 2664 2665 2666 | sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; #endif /* If there was an INDEXED BY clause, then only that one index is ** considered. */ | | | 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 | sqlite3Stat4ProbeFree(pBuilder->pRec); pBuilder->nRecValid = 0; pBuilder->pRec = 0; #endif /* If there was an INDEXED BY clause, then only that one index is ** considered. */ if( pSrc->pIBIndex ) break; } return rc; } #ifndef SQLITE_OMIT_VIRTUALTABLE /* ** Add all WhereLoop objects for a table of the join identified by |
︙ | ︙ | |||
3006 3007 3008 3009 3010 3011 3012 | /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){ Bitmask mUnusable = 0; pNew->iTab = iTab; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); | | | | | 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 | /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); for(iTab=0, pItem=pTabList->a; pItem<pEnd; iTab++, pItem++){ Bitmask mUnusable = 0; pNew->iTab = iTab; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->fg.jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mExtra = mPrior; } priorJointype = pItem->fg.jointype; if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; p<pEnd; p++){ if( mUnusable || (p->fg.jointype & (JT_LEFT|JT_CROSS)) ){ mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); } } rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable); }else{ rc = whereLoopAddBtree(pBuilder, mExtra); } |
︙ | ︙ | |||
3745 3746 3747 3748 3749 3750 3751 | pWInfo = pBuilder->pWInfo; if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; | | | 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 | pWInfo = pBuilder->pWInfo; if( pWInfo->wctrlFlags & WHERE_FORCE_TABLE ) return 0; assert( pWInfo->pTabList->nSrc>=1 ); pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; if( pItem->fg.isIndexedBy ) return 0; iCur = pItem->iCursor; pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); if( pTerm ){ |
︙ | ︙ | |||
4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 | ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_ONETABLE_ONLY flag is set. */ for(ii=0; ii<pTabList->nSrc; ii++){ createMask(pMaskSet, pTabList->a[ii].iCursor); } #ifndef NDEBUG { Bitmask toTheLeft = 0; for(ii=0; ii<pTabList->nSrc; ii++){ Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); assert( (m-1)==toTheLeft ); | > | 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 | ** Note that bitmasks are created for all pTabList->nSrc tables in ** pTabList, not just the first nTabList tables. nTabList is normally ** equal to pTabList->nSrc but might be shortened to 1 if the ** WHERE_ONETABLE_ONLY flag is set. */ for(ii=0; ii<pTabList->nSrc; ii++){ createMask(pMaskSet, pTabList->a[ii].iCursor); sqlite3WhereTabFuncArgs(pParse, &pTabList->a[ii], &pWInfo->sWC); } #ifndef NDEBUG { Bitmask toTheLeft = 0; for(ii=0; ii<pTabList->nSrc; ii++){ Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); assert( (m-1)==toTheLeft ); |
︙ | ︙ | |||
4132 4133 4134 4135 4136 4137 4138 | Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); if( sWLB.pOrderBy ){ tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); } while( pWInfo->nLevel>=2 ){ WhereTerm *pTerm, *pEnd; pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; | | | 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 | Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); if( sWLB.pOrderBy ){ tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); } while( pWInfo->nLevel>=2 ){ WhereTerm *pTerm, *pEnd; pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; if( (pWInfo->pTabList->a[pLoop->iTab].fg.jointype & JT_LEFT)==0 ) break; if( (wctrlFlags & WHERE_WANT_DISTINCT)==0 && (pLoop->wsFlags & WHERE_ONEROW)==0 ){ break; } if( (tabUsed & pLoop->maskSelf)!=0 ) break; pEnd = sWLB.pWC->a + sWLB.pWC->nTerm; |
︙ | ︙ | |||
4425 4426 4427 4428 4429 4430 4431 | assert( pTab!=0 ); pLoop = pLevel->pWLoop; /* For a co-routine, change all OP_Column references to the table of ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ | | | 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 | assert( pTab!=0 ); pLoop = pLevel->pWLoop; /* For a co-routine, change all OP_Column references to the table of ** the co-routine into OP_Copy of result contained in a register. ** OP_Rowid becomes OP_Null. */ if( pTabItem->fg.viaCoroutine && !db->mallocFailed ){ translateColumnToCopy(v, pLevel->addrBody, pLevel->iTabCur, pTabItem->regResult); continue; } /* Close all of the cursors that were opened by sqlite3WhereBegin. ** Except, do not close cursors that will be reused by the OR optimization |
︙ | ︙ |
Changes to src/whereInt.h.
︙ | ︙ | |||
287 288 289 290 291 292 293 | WhereClause *pWC; /* WhereClause currently being scanned */ char *zCollName; /* Required collating sequence, if not NULL */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char nEquiv; /* Number of entries in aEquiv[] */ unsigned char iEquiv; /* Next unused slot in aEquiv[] */ u32 opMask; /* Acceptable operators */ int k; /* Resume scanning at this->pWC->a[this->k] */ | | > | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | WhereClause *pWC; /* WhereClause currently being scanned */ char *zCollName; /* Required collating sequence, if not NULL */ char idxaff; /* Must match this affinity, if zCollName!=NULL */ unsigned char nEquiv; /* Number of entries in aEquiv[] */ unsigned char iEquiv; /* Next unused slot in aEquiv[] */ u32 opMask; /* Acceptable operators */ int k; /* Resume scanning at this->pWC->a[this->k] */ int aiCur[11]; /* Cursors in the equivalence class */ i16 aiColumn[11]; /* Corresponding column number in the eq-class */ }; /* ** An instance of the following structure holds all information about a ** WHERE clause. Mostly this is a container for one or more WhereTerms. ** ** Explanation of pOuter: For a WHERE clause of the form |
︙ | ︙ | |||
471 472 473 474 475 476 477 478 479 480 481 482 483 484 | /* whereexpr.c: */ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); void sqlite3WhereClauseClear(WhereClause*); void sqlite3WhereSplit(WhereClause*,Expr*,u8); Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); /* ** Bitmasks for the operators on WhereTerm objects. These are all | > | 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | /* whereexpr.c: */ void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); void sqlite3WhereClauseClear(WhereClause*); void sqlite3WhereSplit(WhereClause*,Expr*,u8); Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); void sqlite3WhereTabFuncArgs(Parse*, struct SrcList_item*, WhereClause*); /* ** Bitmasks for the operators on WhereTerm objects. These are all |
︙ | ︙ |
Changes to src/wherecode.c.
︙ | ︙ | |||
488 489 490 491 492 493 494 | /* Figure out how many memory cells we will need then allocate them. */ regBase = pParse->nMem + 1; nReg = pLoop->u.btree.nEq + nExtraReg; pParse->nMem += nReg; | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | /* Figure out how many memory cells we will need then allocate them. */ regBase = pParse->nMem + 1; nReg = pLoop->u.btree.nEq + nExtraReg; pParse->nMem += nReg; zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx)); if( !zAff ){ pParse->db->mallocFailed = 1; } if( nSkip ){ int iIdxCur = pLevel->iIdxCur; sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); |
︙ | ︙ | |||
642 643 644 645 646 647 648 | addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); /* If this is the right table of a LEFT OUTER JOIN, allocate and ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ | | | | 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); /* If this is the right table of a LEFT OUTER JOIN, allocate and ** initialize a memory cell that records if this table matches any ** row of the left table of the join. */ if( pLevel->iFrom>0 && (pTabItem[0].fg.jointype & JT_LEFT)!=0 ){ pLevel->iLeftJoin = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); VdbeComment((v, "init LEFT JOIN no-match flag")); } /* Special case of a FROM clause subquery implemented as a co-routine */ if( pTabItem->fg.viaCoroutine ){ int regYield = pTabItem->regReturn; sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); VdbeCoverage(v); VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); pLevel->op = OP_Goto; }else |
︙ | ︙ | |||
1391 1392 1393 1394 1395 1396 1397 | { /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. */ static const u8 aStep[] = { OP_Next, OP_Prev }; static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); | | | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 | { /* Case 6: There is no usable index. We must do a complete ** scan of the entire table. */ static const u8 aStep[] = { OP_Next, OP_Prev }; static const u8 aStart[] = { OP_Rewind, OP_Last }; assert( bRev==0 || bRev==1 ); if( pTabItem->fg.isRecursive ){ /* Tables marked isRecursive have only a single row that is stored in ** a pseudo-cursor. No need to Rewind or Next such cursors. */ pLevel->op = OP_Noop; }else{ pLevel->op = aStep[bRev]; pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); |
︙ | ︙ |
Changes to src/whereexpr.c.
︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 | WhereClause *pWC /* the WHERE clause to be analyzed */ ){ int i; for(i=pWC->nTerm-1; i>=0; i--){ exprAnalyze(pTabList, pWC, i); } } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | WhereClause *pWC /* the WHERE clause to be analyzed */ ){ int i; for(i=pWC->nTerm-1; i>=0; i--){ exprAnalyze(pTabList, pWC, i); } } /* ** For table-valued-functions, transform the function arguments into ** new WHERE clause terms. ** ** Each function argument translates into an equality constraint against ** a HIDDEN column in the table. */ void sqlite3WhereTabFuncArgs( Parse *pParse, /* Parsing context */ struct SrcList_item *pItem, /* The FROM clause term to process */ WhereClause *pWC /* Xfer function arguments to here */ ){ Table *pTab; int j, k; ExprList *pArgs; Expr *pColRef; Expr *pTerm; if( pItem->fg.isTabFunc==0 ) return; pTab = pItem->pTab; assert( pTab!=0 ); pArgs = pItem->u1.pFuncArg; assert( pArgs!=0 ); for(j=k=0; j<pArgs->nExpr; j++){ while( k<pTab->nCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){ k++; } if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", pTab->zName, j); return; } pColRef = sqlite3PExpr(pParse, TK_COLUMN, 0, 0, 0); if( pColRef==0 ) return; pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; pColRef->pTab = pTab; pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } |
Changes to test/join5.test.
︙ | ︙ | |||
156 157 158 159 160 161 162 163 164 | CREATE TABLE x2(b NOT NULL); CREATE TABLE x3(c, d); INSERT INTO x3 VALUES('a', NULL); INSERT INTO x3 VALUES('b', NULL); INSERT INTO x3 VALUES('c', NULL); SELECT * FROM x1 LEFT JOIN x2 JOIN x3 WHERE x3.d = x2.b; } {} finish_test | > > > > > > > > > > > > > > > > > > > > > > > | 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 | CREATE TABLE x2(b NOT NULL); CREATE TABLE x3(c, d); INSERT INTO x3 VALUES('a', NULL); INSERT INTO x3 VALUES('b', NULL); INSERT INTO x3 VALUES('c', NULL); SELECT * FROM x1 LEFT JOIN x2 JOIN x3 WHERE x3.d = x2.b; } {} # Ticket https://www.sqlite.org/src/tktview/c2a19d81652f40568c770c43 on # 2015-08-20. LEFT JOIN and the push-down optimization. # do_execsql_test join6-4.1 { SELECT * FROM ( SELECT 'apple' fruit UNION ALL SELECT 'banana' ) a JOIN ( SELECT 'apple' fruit UNION ALL SELECT 'banana' ) b ON a.fruit=b.fruit LEFT JOIN ( SELECT 1 isyellow ) c ON b.fruit='banana'; } {apple apple {} banana banana 1} do_execsql_test join6-4.2 { SELECT * FROM (SELECT 'apple' fruit UNION ALL SELECT 'banana') LEFT JOIN (SELECT 1) ON fruit='banana'; } {apple {} banana 1} finish_test |
Added test/json101.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # 2015-08-12 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements tests for JSON SQL functions extension to the # SQLite library. # set testdir [file dirname $argv0] source $testdir/tester.tcl load_static_extension db json do_execsql_test json1-1.1 { SELECT json_array(1,2.5,null,'hello'); } {[1,2.5,null,"hello"]} do_execsql_test json1-1.2 { SELECT hex(json_array('String "\ Test')); } {5B22537472696E67205C225C5C2054657374225D} do_catchsql_test json1-1.3 { SELECT json_array(1,2,x'abcd',3); } {1 {JSON cannot hold BLOB values}} do_execsql_test json1-1.4 { SELECT json_array(-9223372036854775808,9223372036854775807,0,1,-1, 0.0, 1.0, -1.0, -1e99, +2e100, 'one','two','three', 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, NULL, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ', 99); } {[-9223372036854775808,9223372036854775807,0,1,-1,0.0,1.0,-1.0,-1.0e+99,2.0e+100,"one","two","three",4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,null,21,22,23,24,25,26,27,28,29,30,31,"abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwyxzABCDEFGHIJKLMNOPQRSTUVWXYZ",99]} do_execsql_test json1-2.1 { SELECT json_object('a',1,'b',2.5,'c',null,'d','String Test'); } {{{"a":1,"b":2.5,"c":null,"d":"String Test"}}} do_catchsql_test json1-2.2 { SELECT json_object('a',1,2,2.5); } {1 {json_object() labels must be TEXT}} do_catchsql_test json1-2.3 { SELECT json_object('a',1,'b'); } {1 {json_object() requires an even number of arguments}} do_catchsql_test json1-2.4 { SELECT json_object('a',1,'b',x'abcd'); } {1 {JSON cannot hold BLOB values}} do_execsql_test json1-3.1 { SELECT json_replace('{"a":1,"b":2}','$.a','[3,4,5]'); } {{{"a":"[3,4,5]","b":2}}} do_execsql_test json1-3.2 { SELECT json_replace('{"a":1,"b":2}','$$.a','[3,4,5]'); } {{{"a":[3,4,5],"b":2}}} do_execsql_test json1-3.3 { SELECT json_type(json_set('{"a":1,"b":2}','$.b','{"x":3,"y":4}'),'$.b'); } {text} do_execsql_test json1-3.4 { SELECT json_type(json_set('{"a":1,"b":2}','$$.b','{"x":3,"y":4}'),'$.b'); } {object} do_execsql_test json1-4.1 { SELECT json_check(' [ 1, 2] '); } {[1,2]} do_catchsql_test json1-4.2 { SELECT json_check(' [ 1, 2 '); } {1 {malformed JSON}} finish_test |
Added test/orderby9.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # 2015-08-26 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file seeks to verify that expressions (and especially functions) # that are in both the ORDER BY clause and the result set are only # evaluated once. # set testdir [file dirname $argv0] source $testdir/tester.tcl set ::testprefix orderby9 do_execsql_test setup { -- create a table with many entries CREATE TABLE t1(x); WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) INSERT INTO t1 SELECT x FROM c; } do_test 1.0 { set l1 {} # If random() is only evaluated once and then reused for each row, then # the output should appear in sorted order. If random() is evaluated # separately for the result set and the ORDER BY clause, then the output # order will be random. db eval {SELECT random() AS y FROM t1 ORDER BY 1;} {lappend l1 $y} expr {$l1==[lsort -int $l1]} } {1} do_test 1.1 { set l1 {} db eval {SELECT random() AS y FROM t1 ORDER BY random();} {lappend l1 $y} expr {$l1==[lsort -int $l1]} } {1} do_test 1.2 { set l1 {} db eval {SELECT random() AS y FROM t1 ORDER BY +random();} {lappend l1 $y} expr {$l1==[lsort -int $l1]} } {0} finish_test |
Added test/parser1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # 2014-08-24 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. # The focus of this script is testing details of the SQL language parser. # set testdir [file dirname $argv0] source $testdir/tester.tcl do_catchsql_test parser1-1.1 { CREATE TABLE t1( a TEXT PRIMARY KEY, b TEXT, FOREIGN KEY(b COLLATE nocase DESC) REFERENCES t1(a COLLATE binary ASC) ); } {1 {syntax error after column name "b"}} # Verify that a legacy schema in the sqlite_master file is allowed to have # COLLATE, ASC, and DESC keywords on the id list of a FK constraint, and that # those keywords are silently ignored. # do_execsql_test parser1-1.2 { CREATE TABLE t1( a TEXT PRIMARY KEY, b TEXT, FOREIGN KEY(b) REFERENCES t1(a) ); INSERT INTO t1 VALUES('abc',NULL),('xyz','abc'); PRAGMA writable_schema=on; UPDATE sqlite_master SET sql='CREATE TABLE t1( a TEXT PRIMARY KEY, b TEXT, FOREIGN KEY(b COLLATE nocase) REFERENCES t1(a) )' WHERE name='t1'; SELECT name FROM sqlite_master WHERE sql LIKE '%collate%'; } {t1} sqlite3 db2 test.db do_test parser1-1.3 { sqlite3 db2 test.db db2 eval {SELECT * FROM t1 ORDER BY 1} } {abc {} xyz abc} db2 close do_execsql_test parser1-1.4 { UPDATE sqlite_master SET sql='CREATE TABLE t1( a TEXT PRIMARY KEY, b TEXT, FOREIGN KEY(b ASC) REFERENCES t1(a) )' WHERE name='t1'; SELECT name FROM sqlite_master WHERE sql LIKE '%ASC%'; } {t1} sqlite3 db2 test.db do_test parser1-1.5 { sqlite3 db2 test.db db2 eval {SELECT * FROM t1 ORDER BY 1} } {abc {} xyz abc} db2 close do_catchsql_test parser1-2.1 { WITH RECURSIVE c(x COLLATE binary) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5) SELECT x FROM c; } {1 {syntax error after column name "x"}} do_catchsql_test parser1-2.2 { WITH RECURSIVE c(x ASC) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE x<5) SELECT x FROM c; } {1 {syntax error after column name "x"}} finish_test |
Changes to test/releasetest.tcl.
︙ | ︙ | |||
282 283 284 285 286 287 288 289 290 291 292 293 294 295 | if {0==[info exists ::Configs($v)]} { puts stderr "No such configuration: \"$v\"" exit -1 } } } # Open the file $logfile and look for a report on the number of errors # and the number of test cases run. Add these values to the global # $::NERRCASE and $::NTESTCASE variables. # # If any errors occur, then write into $errmsgVar the text of an appropriate # one-line error message to show on the output. # | > > > > > > > > > > > > > > > > | 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 | if {0==[info exists ::Configs($v)]} { puts stderr "No such configuration: \"$v\"" exit -1 } } } # Output log # set LOG [open releasetest-out.txt w] proc PUTS {args} { if {[llength $args]==2} { puts [lindex $args 0] [lindex $args 1] puts [lindex $args 0] $::LOG [lindex $args 1] } else { puts [lindex $args 0] puts $::LOG [lindex $args 0] } } puts $LOG "$argv0 $argv" set tm0 [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S} -gmt 1] puts $LOG "start-time: $tm0 UTC" # Open the file $logfile and look for a report on the number of errors # and the number of test cases run. Add these values to the global # $::NERRCASE and $::NTESTCASE variables. # # If any errors occur, then write into $errmsgVar the text of an appropriate # one-line error message to show on the output. # |
︙ | ︙ | |||
404 405 406 407 408 409 410 | append opts " -DSQLITE_OS_WIN=1" } else { append opts " -DSQLITE_OS_UNIX=1" } if {!$::TRACE} { set n [string length $title] | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 | append opts " -DSQLITE_OS_WIN=1" } else { append opts " -DSQLITE_OS_UNIX=1" } if {!$::TRACE} { set n [string length $title] PUTS -nonewline "${title}[string repeat . [expr {63-$n}]]" flush stdout } set rc 0 set tm1 [clock seconds] set origdir [pwd] trace_cmd file mkdir $dir |
︙ | ︙ | |||
429 430 431 432 433 434 435 | if {!$::TRACE} { set hours [expr {($tm2-$tm1)/3600}] set minutes [expr {(($tm2-$tm1)/60)%60}] set seconds [expr {($tm2-$tm1)%60}] set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] if {$rc} { | | | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | if {!$::TRACE} { set hours [expr {($tm2-$tm1)/3600}] set minutes [expr {(($tm2-$tm1)/60)%60}] set seconds [expr {($tm2-$tm1)%60}] set tm [format (%02d:%02d:%02d) $hours $minutes $seconds] if {$rc} { PUTS " FAIL $tm" incr ::NERR } else { PUTS " Ok $tm" } if {$errmsg!=""} {PUTS " $errmsg"} } } # The following procedure returns the "configure" command to be exectued for # the current platform, which may be Windows (via MinGW, etc). # proc configureCommand {opts} { |
︙ | ︙ | |||
476 477 478 479 480 481 482 | # The following procedure prints its arguments if ::TRACE is true. # And it executes the command of its arguments in the calling context # if ::DRYRUN is false. # proc trace_cmd {args} { if {$::TRACE} { | | | 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | # The following procedure prints its arguments if ::TRACE is true. # And it executes the command of its arguments in the calling context # if ::DRYRUN is false. # proc trace_cmd {args} { if {$::TRACE} { PUTS $args } if {!$::DRYRUN} { uplevel 1 $args } } |
︙ | ︙ | |||
544 545 546 547 548 549 550 | } -trace { set ::TRACE 1 } -info { | | | | | | | | | | | | | | | | 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 | } -trace { set ::TRACE 1 } -info { PUTS "Command-line Options:" PUTS " --srcdir $::SRCDIR" PUTS " --platform [list $platform]" PUTS " --config [list $config]" if {$::QUICK} { if {$::QUICK==1} {PUTS " --quick"} if {$::QUICK==2} {PUTS " --veryquick"} } if {$::MSVC} {PUTS " --msvc"} if {$::BUILDONLY} {PUTS " --buildonly"} if {$::DRYRUN} {PUTS " --dryrun"} if {$::TRACE} {PUTS " --trace"} PUTS "\nAvailable --platform options:" foreach y [lsort [array names ::Platforms]] { PUTS " [list $y]" } PUTS "\nAvailable --config options:" foreach y [lsort [array names ::Configs]] { PUTS " [list $y]" } exit } -g { if {$::MSVC} { lappend ::EXTRACONFIG -Zi |
︙ | ︙ | |||
588 589 590 591 592 593 594 | -enable-* - -disable-* - *=* { lappend ::EXTRACONFIG [lindex $argv $i] } default { | | | | | | | | | | | | | | | | | | 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 | -enable-* - -disable-* - *=* { lappend ::EXTRACONFIG [lindex $argv $i] } default { PUTS stderr "" PUTS stderr [string trim $::USAGE_MESSAGE] exit -1 } } } if {0==[info exists ::Platforms($platform)]} { PUTS "Unknown platform: $platform" PUTS -nonewline "Set the -platform option to " set print [list] foreach p [array names ::Platforms] { lappend print "\"$p\"" } lset print end "or [lindex $print end]" PUTS "[join $print {, }]." exit } if {$config!=""} { if {[llength $config]==1} {lappend config fulltest} set ::CONFIGLIST $config } else { set ::CONFIGLIST $::Platforms($platform) } PUTS "Running the following test configurations for $platform:" PUTS " [string trim $::CONFIGLIST]" PUTS -nonewline "Flags:" if {$::DRYRUN} {PUTS -nonewline " --dryrun"} if {$::BUILDONLY} {PUTS -nonewline " --buildonly"} if {$::MSVC} {PUTS -nonewline " --msvc"} switch -- $::QUICK { 1 {PUTS -nonewline " --quick"} 2 {PUTS -nonewline " --veryquick"} } PUTS "" } # Main routine. # proc main {argv} { # Process any command line options. set ::EXTRACONFIG {} process_options $argv PUTS [string repeat * 79] set ::NERR 0 set ::NTEST 0 set ::NTESTCASE 0 set ::NERRCASE 0 set ::SQLITE_VERSION {} set STARTTIME [clock seconds] foreach {zConfig target} $::CONFIGLIST { if {$::MSVC && ($zConfig eq "Sanitize" || "checksymbols" in $target || "valgrindtest" in $target)} { PUTS "Skipping $zConfig / $target for MSVC..." continue } if {$target ne "checksymbols"} { switch -- $::QUICK { 1 {set target quicktest} 2 {set target smoketest} } |
︙ | ︙ | |||
689 690 691 692 693 694 695 | } set elapsetime [expr {[clock seconds]-$STARTTIME}] set hr [expr {$elapsetime/3600}] set min [expr {($elapsetime/60)%60}] set sec [expr {$elapsetime%60}] set etime [format (%02d:%02d:%02d) $hr $min $sec] | | | | | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 | } set elapsetime [expr {[clock seconds]-$STARTTIME}] set hr [expr {$elapsetime/3600}] set min [expr {($elapsetime/60)%60}] set sec [expr {$elapsetime%60}] set etime [format (%02d:%02d:%02d) $hr $min $sec] PUTS [string repeat * 79] PUTS "$::NERRCASE failures out of $::NTESTCASE tests in $etime" if {$::SQLITE_VERSION ne ""} { PUTS "SQLite $::SQLITE_VERSION" } } main $argv |
Added test/spellfix2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # 2012 July 12 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix spellfix2 ifcapable !vtab { finish_test ; return } load_static_extension db spellfix nextchar do_execsql_test 1.0 { CREATE VIRTUAL TABLE demo USING spellfix1; INSERT INTO demo(word) VALUES ('amsterdam'); INSERT INTO demo(word) VALUES ('amsterdammetje'); INSERT INTO demo(word) VALUES ('amsterdamania'); INSERT INTO demo(word) VALUES ('amsterdamweg'); INSERT INTO demo(word) VALUES ('amsterdamsestraat'); INSERT INTO demo(word) VALUES ('amsterdamlaan'); } do_execsql_test 1.1 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND top=3; } { amsterdam 100 9 amsterdammetje 100 9 amsterdamania 100 9 } do_execsql_test 1.2 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND top=3 AND distance <= 100; } { amsterdam 100 9 amsterdammetje 100 9 amsterdamania 100 9 } do_execsql_test 1.3 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100; } { amsterdam 100 9 amsterdammetje 100 9 amsterdamania 100 9 amsterdamweg 100 9 amsterdamsestraat 100 9 amsterdamlaan 100 9 } do_test 1.4 { foreach l {a b c d e f g h i j k l m n o p q r s t u v w x y z} { execsql { INSERT INTO demo(word) VALUES ('amsterdam' || $l) } } } {} do_execsql_test 1.5 { SELECT count(*) FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100; SELECT count(*) FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20; } { 32 20 } do_execsql_test 1.6 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100; } { amsterdam 100 9 amsterdamh 100 9 amsterdamm 100 9 amsterdamn 100 9 amsterdama 100 9 amsterdame 100 9 amsterdami 100 9 amsterdamo 100 9 amsterdamu 100 9 amsterdamy 100 9 amsterdammetje 100 9 amsterdamania 100 9 amsterdamb 100 9 amsterdamf 100 9 amsterdamp 100 9 amsterdamv 100 9 amsterdamw 100 9 amsterdamweg 100 9 amsterdamc 100 9 amsterdamg 100 9 amsterdamj 100 9 amsterdamk 100 9 amsterdamq 100 9 amsterdams 100 9 amsterdamx 100 9 amsterdamz 100 9 amsterdamsestraat 100 9 amsterdamd 100 9 amsterdamt 100 9 amsterdaml 100 9 amsterdamlaan 100 9 amsterdamr 100 9 } do_execsql_test 1.7 { SELECT word, distance, matchlen FROM demo WHERE word MATCH 'amstedam*' AND distance <= 100 AND top=20; } { amsterdam 100 9 amsterdamh 100 9 amsterdamm 100 9 amsterdamn 100 9 amsterdama 100 9 amsterdame 100 9 amsterdami 100 9 amsterdamo 100 9 amsterdamu 100 9 amsterdamy 100 9 amsterdammetje 100 9 amsterdamania 100 9 amsterdamb 100 9 amsterdamf 100 9 amsterdamp 100 9 amsterdamv 100 9 amsterdamw 100 9 amsterdamweg 100 9 amsterdamc 100 9 amsterdamg 100 9 } finish_test |
Added test/tabfunc01.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | # 2015-08-19 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # This file implements tests for table-valued-functions implemented using # eponymous virtual tables. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix tabfunc01 ifcapable !vtab { finish_test return } load_static_extension db series do_execsql_test tabfunc01-1.1 { SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2; } {1 | 3 | 5 | 7 | 9 |} do_execsql_test tabfunc01-1.2 { SELECT *, '|' FROM generate_series LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} do_catchsql_test tabfunc01-1.3 { CREATE VIRTUAL TABLE t1 USING generate_series; } {1 {no such module: generate_series}} do_execsql_test tabfunc01-1.4 { SELECT * FROM generate_series(1,9,2); } {1 3 5 7 9} do_execsql_test tabfunc01-1.5 { SELECT * FROM generate_series(1,9); } {1 2 3 4 5 6 7 8 9} do_execsql_test tabfunc01-1.6 { SELECT * FROM generate_series(1,10) WHERE step=3; } {1 4 7 10} do_catchsql_test tabfunc01-1.7 { SELECT * FROM generate_series(1,9,2,11); } {1 {too many arguments on generate_series() - max 3}} do_execsql_test tabfunc01-1.8 { SELECT * FROM generate_series(0,32,5) ORDER BY rowid DESC; } {30 25 20 15 10 5 0} do_execsql_test tabfunc01-1.9 { SELECT rowid, * FROM generate_series(0,32,5) ORDER BY value DESC; } {1 30 2 25 3 20 4 15 5 10 6 5 7 0} do_execsql_test tabfunc01-1.10 { SELECT rowid, * FROM generate_series(0,32,5) ORDER BY +value DESC; } {7 30 6 25 5 20 4 15 3 10 2 5 1 0} do_execsql_test tabfunc01-2.1 { CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(2),(3); SELECT *, '|' FROM t1, generate_series(1,x) ORDER BY 1, 2 } {2 1 | 2 2 | 3 1 | 3 2 | 3 3 |} do_execsql_test tabfunc01-2.2 { SELECT * FROM generate_series() LIMIT 5; } {0 1 2 3 4} do_execsql_test tabfunc01-3.1 { SELECT DISTINCT value FROM generate_series(1,x), t1 ORDER BY 1; } {1 2 3} finish_test |
Changes to test/view.test.
︙ | ︙ | |||
148 149 150 151 152 153 154 155 156 157 158 159 160 161 | } {xyz 2 pqr 7 c-b 1} do_test view-3.3.2 { execsql2 { CREATE VIEW v1b AS SELECT t1.a, b+c, t1.c FROM t1; SELECT * FROM v1b LIMIT 1 } } {a 2 b+c 7 c 4} ifcapable compound { do_test view-3.4 { execsql2 { CREATE VIEW v3 AS SELECT a FROM t1 UNION SELECT b FROM t1 ORDER BY b; SELECT * FROM v3 LIMIT 4; } | > > > > > > > > > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | } {xyz 2 pqr 7 c-b 1} do_test view-3.3.2 { execsql2 { CREATE VIEW v1b AS SELECT t1.a, b+c, t1.c FROM t1; SELECT * FROM v1b LIMIT 1 } } {a 2 b+c 7 c 4} do_test view-3.3.3 { execsql2 { CREATE VIEW v1c(x,y,z) AS SELECT a, b+c, c-b FROM t1; SELECT * FROM v1c LIMIT 1; } } {x 2 y 7 z 1} do_catchsql_test view-3.3.4 { CREATE VIEW v1err(x,y DESC,z) AS SELECT a, b+c, c-b FROM t1; } {1 {syntax error after column name "y"}} ifcapable compound { do_test view-3.4 { execsql2 { CREATE VIEW v3 AS SELECT a FROM t1 UNION SELECT b FROM t1 ORDER BY b; SELECT * FROM v3 LIMIT 4; } |
︙ | ︙ | |||
333 334 335 336 337 338 339 | sqlite3 db test.db execsql { SELECT * FROM v6 ORDER BY xyz; } } {7 2 13 5 19 8 27 12} do_test view-8.3 { execsql { | | | 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | sqlite3 db test.db execsql { SELECT * FROM v6 ORDER BY xyz; } } {7 2 13 5 19 8 27 12} do_test view-8.3 { execsql { CREATE VIEW v7(a) AS SELECT pqr+xyz FROM v6; SELECT * FROM v7 ORDER BY a; } } {9 18 27 39} ifcapable subquery { do_test view-8.4 { execsql { |
︙ | ︙ |
Changes to test/where2.test.
︙ | ︙ | |||
318 319 320 321 322 323 324 | do_test where2-6.3 { queryplan { SELECT * FROM t1 WHERE w=99 OR w=100 OR 6=+w ORDER BY +w } } {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 *} do_test where2-6.4 { queryplan { | | | > > > > > | 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | do_test where2-6.3 { queryplan { SELECT * FROM t1 WHERE w=99 OR w=100 OR 6=+w ORDER BY +w } } {6 2 49 51 99 6 10000 10006 100 6 10201 10207 sort t1 *} do_test where2-6.4 { queryplan { SELECT *, '|' FROM t1 WHERE w=99 OR +w=100 OR 6=w ORDER BY +w } } {6 2 49 51 | 99 6 10000 10006 | 100 6 10201 10207 | sort t1 *} do_test where2-6.5 { queryplan { SELECT *, '|' FROM t1 WHERE w=99 OR y=10201 OR 6=w ORDER BY +w } } {6 2 49 51 | 99 6 10000 10006 | 100 6 10201 10207 | sort t1 *} set ::idx {} ifcapable subquery {set ::idx i1zyx} do_test where2-6.5 { queryplan { SELECT b.* FROM t1 a, t1 b WHERE a.w=1 AND (a.y=b.z OR b.z=10) |
︙ | ︙ |
Changes to test/with2.test.
︙ | ︙ | |||
246 247 248 249 250 251 252 | do_execsql_test 4.2 [genstmt 10] 1 do_execsql_test 4.3 [genstmt 100] 1 do_execsql_test 4.4 [genstmt 255] 1 set nLimit [sqlite3_limit db SQLITE_LIMIT_COLUMN -1] do_execsql_test 4.5 [genstmt [expr $nLimit-1]] 1 do_execsql_test 4.6 [genstmt $nLimit] 1 | | > | 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | do_execsql_test 4.2 [genstmt 10] 1 do_execsql_test 4.3 [genstmt 100] 1 do_execsql_test 4.4 [genstmt 255] 1 set nLimit [sqlite3_limit db SQLITE_LIMIT_COLUMN -1] do_execsql_test 4.5 [genstmt [expr $nLimit-1]] 1 do_execsql_test 4.6 [genstmt $nLimit] 1 do_catchsql_test 4.7 [genstmt [expr $nLimit+1]] \ {1 {too many columns in result set}} #--------------------------------------------------------------------------- # Check that adding a WITH clause to an INSERT disables the xfer # optimization. # proc do_xfer_test {tn bXfer sql {res {}}} { set ::sqlite3_xferopt_count 0 |
︙ | ︙ | |||
411 412 413 414 415 416 417 | SELECT a+1 FROM q, v WHERE a<5 ) SELECT * FROM q; } {1 2 3 4 5} finish_test | < | 412 413 414 415 416 417 418 | SELECT a+1 FROM q, v WHERE a<5 ) SELECT * FROM q; } {1 2 3 4 5} finish_test |
Changes to tool/build-all-msvc.bat.
︙ | ︙ | |||
307 308 309 310 311 312 313 314 315 316 317 318 319 | REM NOTE: If the Universal CRT library path has already been set, do not set REM it to something else later on. REM IF NOT DEFINED NUCRTLIBPATH ( SET SET_NUCRTLIBPATH=1 ) ) REM REM NOTE: This is the name of the sub-directory where the Windows 10.0 SDK REM libraries may be found. It is only used when compiling with the REM Windows 10.0 SDK. REM | > > > > > > > > > > > > > | > | 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 | REM NOTE: If the Universal CRT library path has already been set, do not set REM it to something else later on. REM IF NOT DEFINED NUCRTLIBPATH ( SET SET_NUCRTLIBPATH=1 ) ) REM REM NOTE: This is the name of the sub-directory where the UCRT libraries may REM be found. It is only used when compiling against the UCRT. REM IF DEFINED UCRTVersion ( SET NUCRTVER=%UCRTVersion% ) ELSE ( SET NUCRTVER=10.0.10240.0 ) REM REM NOTE: This is the name of the sub-directory where the Windows 10.0 SDK REM libraries may be found. It is only used when compiling with the REM Windows 10.0 SDK. REM IF DEFINED WindowsSDKLibVersion ( SET WIN10SDKVER=%WindowsSDKLibVersion:\=% ) ELSE ( SET WIN10SDKVER=%NUCRTVER% ) REM REM NOTE: Check if this is the Windows Phone SDK. If so, a different batch REM file is necessary to setup the build environment. Since the variable REM values involved here may contain parenthesis, using GOTO instead of REM an IF block is required. REM |
︙ | ︙ | |||
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 | REM REM NOTE: Attempt to clean the environment of all variables used by MSVC REM and/or Visual Studio. This block may need to be updated in the REM future to account for additional environment variables. REM CALL :fn_UnsetVariable CommandPromptType CALL :fn_UnsetVariable DevEnvDir CALL :fn_UnsetVariable ExtensionSdkDir CALL :fn_UnsetVariable Framework35Version CALL :fn_UnsetVariable Framework40Version CALL :fn_UnsetVariable FrameworkDir CALL :fn_UnsetVariable FrameworkDir32 CALL :fn_UnsetVariable FrameworkVersion CALL :fn_UnsetVariable FrameworkVersion32 CALL :fn_UnsetVariable FSHARPINSTALLDIR CALL :fn_UnsetVariable INCLUDE CALL :fn_UnsetVariable LIB CALL :fn_UnsetVariable LIBPATH CALL :fn_UnsetVariable Platform CALL :fn_UnsetVariable UniversalCRTSdkDir REM CALL :fn_UnsetVariable VCINSTALLDIR CALL :fn_UnsetVariable VSINSTALLDIR CALL :fn_UnsetVariable WindowsPhoneKitDir CALL :fn_UnsetVariable WindowsSdkDir CALL :fn_UnsetVariable WindowsSdkDir_35 CALL :fn_UnsetVariable WindowsSdkDir_old CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x86 CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x64 REM REM NOTE: Reset the PATH here to the absolute bare minimum required. REM SET PATH=%TOOLPATH%;%SystemRoot%\System32;%SystemRoot% | > > > > > > | 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 | REM REM NOTE: Attempt to clean the environment of all variables used by MSVC REM and/or Visual Studio. This block may need to be updated in the REM future to account for additional environment variables. REM CALL :fn_UnsetVariable CommandPromptType CALL :fn_UnsetVariable DevEnvDir CALL :fn_UnsetVariable DNX_HOME CALL :fn_UnsetVariable ExtensionSdkDir CALL :fn_UnsetVariable Framework35Version CALL :fn_UnsetVariable Framework40Version CALL :fn_UnsetVariable FrameworkDir CALL :fn_UnsetVariable FrameworkDir32 CALL :fn_UnsetVariable FrameworkVersion CALL :fn_UnsetVariable FrameworkVersion32 CALL :fn_UnsetVariable FSHARPINSTALLDIR CALL :fn_UnsetVariable INCLUDE CALL :fn_UnsetVariable LIB CALL :fn_UnsetVariable LIBPATH CALL :fn_UnsetVariable NETFXSDKDir CALL :fn_UnsetVariable Platform CALL :fn_UnsetVariable UCRTVersion CALL :fn_UnsetVariable UniversalCRTSdkDir REM CALL :fn_UnsetVariable VCINSTALLDIR CALL :fn_UnsetVariable VSINSTALLDIR CALL :fn_UnsetVariable WindowsLibPath CALL :fn_UnsetVariable WindowsPhoneKitDir CALL :fn_UnsetVariable WindowsSdkDir CALL :fn_UnsetVariable WindowsSdkDir_35 CALL :fn_UnsetVariable WindowsSdkDir_old CALL :fn_UnsetVariable WindowsSDKLibVersion CALL :fn_UnsetVariable WindowsSDKVersion CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x86 CALL :fn_UnsetVariable WindowsSDK_ExecutablePath_x64 REM REM NOTE: Reset the PATH here to the absolute bare minimum required. REM SET PATH=%TOOLPATH%;%SystemRoot%\System32;%SystemRoot% |
︙ | ︙ | |||
485 486 487 488 489 490 491 | CALL :fn_CopyVariable WindowsSdkDir NSDKLIBPATH REM REM NOTE: The Windows 8.x and Windows 10.0 SDKs have a slightly REM different directory naming conventions. REM IF DEFINED USE_WINV100_NSDKLIBPATH ( | | | | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 | CALL :fn_CopyVariable WindowsSdkDir NSDKLIBPATH REM REM NOTE: The Windows 8.x and Windows 10.0 SDKs have a slightly REM different directory naming conventions. REM IF DEFINED USE_WINV100_NSDKLIBPATH ( CALL :fn_AppendVariable NSDKLIBPATH \..\10\lib\%WIN10SDKVER%\um\x86 CALL :fn_CopyVariable WindowsSdkDir PSDKLIBPATH CALL :fn_AppendVariable PSDKLIBPATH lib\%WIN10SDKVER%\um\%%D ) ELSE IF DEFINED USE_WINV63_NSDKLIBPATH ( CALL :fn_AppendVariable NSDKLIBPATH \lib\winv6.3\um\x86 ) ELSE IF "%VisualStudioVersion%" == "12.0" ( CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86 ) ELSE IF "%VisualStudioVersion%" == "14.0" ( CALL :fn_AppendVariable NSDKLIBPATH \..\8.0\lib\win8\um\x86 ) ELSE ( |
︙ | ︙ | |||
510 511 512 513 514 515 516 | REM each iteration because it relies upon the UniversalCRTSdkDir REM environment variable being set by the batch file used to REM setup the MSVC environment. REM IF DEFINED SET_NUCRTLIBPATH ( IF DEFINED UniversalCRTSdkDir ( CALL :fn_CopyVariable UniversalCRTSdkDir NUCRTLIBPATH | | | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | REM each iteration because it relies upon the UniversalCRTSdkDir REM environment variable being set by the batch file used to REM setup the MSVC environment. REM IF DEFINED SET_NUCRTLIBPATH ( IF DEFINED UniversalCRTSdkDir ( CALL :fn_CopyVariable UniversalCRTSdkDir NUCRTLIBPATH CALL :fn_AppendVariable NUCRTLIBPATH \lib\%NUCRTVER%\ucrt\x86 ) ) REM REM NOTE: Unless prevented from doing so, invoke NMAKE with the MSVC REM makefile to clean any stale build output from previous REM iterations of this loop and/or previous runs of this batch |
︙ | ︙ |
Changes to tool/sqldiff.c.
︙ | ︙ | |||
806 807 808 809 810 811 812 | } /* ** Advance the rolling hash by a single character "c" */ static void hash_next(hash *pHash, int c){ u16 old = pHash->z[pHash->i]; | | | | 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | } /* ** Advance the rolling hash by a single character "c" */ static void hash_next(hash *pHash, int c){ u16 old = pHash->z[pHash->i]; pHash->z[pHash->i] = (char)c; pHash->i = (pHash->i+1)&(NHASH-1); pHash->a = pHash->a - old + (char)c; pHash->b = pHash->b - NHASH*old + pHash->a; } /* ** Return a 32-bit hash value */ static u32 hash_32bit(hash *pHash){ |
︙ | ︙ | |||
845 846 847 848 849 850 851 | } /* ** Return the number digits in the base-64 representation of a positive integer */ static int digit_count(int v){ unsigned int i, x; | | | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 | } /* ** Return the number digits in the base-64 representation of a positive integer */ static int digit_count(int v){ unsigned int i, x; for(i=1, x=64; (unsigned int)v>=x; i++, x <<= 6){} return i; } /* ** Compute a 32-bit checksum on the N-byte buffer. Return the result. */ static unsigned int checksum(const char *zIn, size_t N){ |
︙ | ︙ | |||
952 953 954 955 956 957 958 | static int rbuDeltaCreate( const char *zSrc, /* The source or pattern file */ unsigned int lenSrc, /* Length of the source file */ const char *zOut, /* The target file */ unsigned int lenOut, /* Length of the target file */ char *zDelta /* Write the delta into this buffer */ ){ | | | 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 | static int rbuDeltaCreate( const char *zSrc, /* The source or pattern file */ unsigned int lenSrc, /* Length of the source file */ const char *zOut, /* The target file */ unsigned int lenOut, /* Length of the target file */ char *zDelta /* Write the delta into this buffer */ ){ unsigned int i, base; char *zOrigDelta = zDelta; hash h; int nHash; /* Number of hash table entries */ int *landmark; /* Primary hash table */ int *collide; /* Collision chain */ int lastRead = -1; /* Last byte of zSrc read by a COPY command */ |
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | /* Begin scanning the target file and generating copy commands and ** literal sections of the delta. */ base = 0; /* We have already generated everything before zOut[base] */ while( base+NHASH<lenOut ){ int iSrc, iBlock; | | | 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 | /* Begin scanning the target file and generating copy commands and ** literal sections of the delta. */ base = 0; /* We have already generated everything before zOut[base] */ while( base+NHASH<lenOut ){ int iSrc, iBlock; int bestCnt, bestOfst=0, bestLitsz=0; hash_init(&h, &zOut[base]); i = 0; /* Trying to match a landmark against zOut[base+i] */ bestCnt = 0; while( 1 ){ int hv; int limit = 250; |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | int cnt, ofst, litsz; int j, k, x, y; int sz; /* Beginning at iSrc, match forwards as far as we can. j counts ** the number of characters that match */ iSrc = iBlock*NHASH; | > | > > > | | 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 | int cnt, ofst, litsz; int j, k, x, y; int sz; /* Beginning at iSrc, match forwards as far as we can. j counts ** the number of characters that match */ iSrc = iBlock*NHASH; for( j=0, x=iSrc, y=base+i; (unsigned int)x<lenSrc && (unsigned int)y<lenOut; j++, x++, y++ ){ if( zSrc[x]!=zOut[y] ) break; } j--; /* Beginning at iSrc-1, match backwards as far as we can. k counts ** the number of characters that match */ for(k=1; k<iSrc && (unsigned int)k<=i; k++){ if( zSrc[iSrc-k]!=zOut[base+i-k] ) break; } k--; /* Compute the offset and size of the matching region */ ofst = iSrc-k; cnt = j+k+1; |
︙ | ︙ |